diff --git a/staging/operator-lifecycle-manager/.gitignore b/staging/operator-lifecycle-manager/.gitignore index 4efa7ce90a..5c77f3d21b 100644 --- a/staging/operator-lifecycle-manager/.gitignore +++ b/staging/operator-lifecycle-manager/.gitignore @@ -455,5 +455,5 @@ apiserver.key !vendor/** test/e2e-local.image.tar - +test/e2e/.kube dist/ diff --git a/staging/operator-lifecycle-manager/.golangci.yaml b/staging/operator-lifecycle-manager/.golangci.yaml index b0b322a52f..cd7c8b71bb 100644 --- a/staging/operator-lifecycle-manager/.golangci.yaml +++ b/staging/operator-lifecycle-manager/.golangci.yaml @@ -21,6 +21,24 @@ linters: disable: - errcheck +linters-settings: + importas: + alias: + - pkg: k8s.io/api/core/v1 + alias: corev1 + - pkg: k8s.io/api/apps/v1 + alias: appsv1 + - pkg: k8s.io/apimachinery/pkg/apis/meta/v1 + alias: metav1 + - pkg: k8s.io/apimachinery/pkg/api/errors + alias: apierrors + - pkg: github.com/operator-framework/api/pkg/operators/v1alpha1 + alias: operatorsv1alpha1 + - pkg: github.com/operator-framework/api/pkg/operators/v1 + alias: operatorsv1 + - pkg: github.com/operator-framework/api/pkg/operators/v2 + alias: operatorsv2 + issues: max-issues-per-linter: 0 max-same-issues: 0 diff --git a/staging/operator-lifecycle-manager/Makefile b/staging/operator-lifecycle-manager/Makefile index 001008f3ea..6220e2f24d 100644 --- a/staging/operator-lifecycle-manager/Makefile +++ b/staging/operator-lifecycle-manager/Makefile @@ -139,11 +139,10 @@ E2E_TEST_NS ?= operators e2e: $(GINKGO) $(E2E_OPTS) $(or $(run), ./test/e2e) $< -- -namespace=$(E2E_TEST_NS) -olmNamespace=$(E2E_INSTALL_NS) -dummyImage=bitnami/nginx:latest $(or $(extra_args), -kubeconfig=${KUBECONFIG}) - # See workflows/e2e-tests.yml See test/e2e/README.md for details. .PHONY: e2e-local e2e-local: BUILD_TAGS="json1 experimental_metrics" -e2e-local: extra_args=-kind.images=../test/e2e-local.image.tar -test-data-dir=../test/e2e/testdata +e2e-local: extra_args=-kind.images=../test/e2e-local.image.tar -test-data-dir=../test/e2e/testdata -gather-artifacts-script-path=../test/e2e/collect-ci-artifacts.sh e2e-local: run=bin/e2e-local.test e2e-local: bin/e2e-local.test test/e2e-local.image.tar e2e-local: e2e diff --git a/staging/operator-lifecycle-manager/cmd/olm/main.go b/staging/operator-lifecycle-manager/cmd/olm/main.go index 463526c086..7786f5b823 100644 --- a/staging/operator-lifecycle-manager/cmd/olm/main.go +++ b/staging/operator-lifecycle-manager/cmd/olm/main.go @@ -13,7 +13,7 @@ import ( configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1" "github.com/sirupsen/logrus" "github.com/spf13/pflag" - v1 "k8s.io/api/core/v1" + corev1 "k8s.io/api/core/v1" "k8s.io/klog" ctrl "sigs.k8s.io/controller-runtime" @@ -103,8 +103,8 @@ func main() { // the empty string, the resulting array will be `[]string{""}`. namespaces := strings.Split(*watchedNamespaces, ",") for _, ns := range namespaces { - if ns == v1.NamespaceAll { - namespaces = []string{v1.NamespaceAll} + if ns == corev1.NamespaceAll { + namespaces = []string{corev1.NamespaceAll} break } } diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/apiservice.go b/staging/operator-lifecycle-manager/pkg/controller/install/apiservice.go index 1f1061c43b..9d17e1664c 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/apiservice.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/apiservice.go @@ -6,7 +6,7 @@ import ( "strings" log "github.com/sirupsen/logrus" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" @@ -26,7 +26,7 @@ func (i *StrategyDeploymentInstaller) createOrUpdateAPIService(caPEM []byte, des exists := true apiService, err := i.strategyClient.GetOpLister().APIRegistrationV1().APIServiceLister().Get(apiServiceName) if err != nil { - if !k8serrors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return err } @@ -120,14 +120,14 @@ func IsAPIServiceAdoptable(opLister operatorlister.OperatorLister, target *v1alp // Get the CSV that target replaces replacing, replaceGetErr := opLister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(target.GetNamespace()).Get(target.Spec.Replaces) - if replaceGetErr != nil && !k8serrors.IsNotFound(replaceGetErr) && !k8serrors.IsGone(replaceGetErr) { + if replaceGetErr != nil && !apierrors.IsNotFound(replaceGetErr) && !apierrors.IsGone(replaceGetErr) { err = replaceGetErr return } // Get the current owner CSV of the APIService currentOwnerCSV, ownerGetErr := opLister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(ownerNamespace).Get(ownerName) - if ownerGetErr != nil && !k8serrors.IsNotFound(ownerGetErr) && !k8serrors.IsGone(ownerGetErr) { + if ownerGetErr != nil && !apierrors.IsNotFound(ownerGetErr) && !apierrors.IsGone(ownerGetErr) { err = ownerGetErr return } @@ -179,13 +179,13 @@ func (i *StrategyDeploymentInstaller) deleteLegacyAPIServiceResources(desc apiSe // Attempt to delete the legacy Service. existingService, err := i.strategyClient.GetOpClient().GetService(namespace, legacyServiceName) if err != nil { - if !k8serrors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return err } } else if ownerutil.AdoptableLabels(existingService.GetLabels(), true, i.owner) { logger.Infof("Deleting Service with legacy APIService name %s", existingService.Name) err = i.strategyClient.GetOpClient().DeleteService(namespace, legacyServiceName, &metav1.DeleteOptions{}) - if err != nil && !k8serrors.IsNotFound(err) { + if err != nil && !apierrors.IsNotFound(err) { return err } } else { @@ -198,13 +198,13 @@ func (i *StrategyDeploymentInstaller) deleteLegacyAPIServiceResources(desc apiSe // Attempt to delete the legacy Secret. existingSecret, err := i.strategyClient.GetOpClient().GetSecret(namespace, SecretName(apiServiceName)) if err != nil { - if !k8serrors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return err } } else if ownerutil.AdoptableLabels(existingSecret.GetLabels(), true, i.owner) { logger.Infof("Deleting Secret with legacy APIService name %s", existingSecret.Name) err = i.strategyClient.GetOpClient().DeleteSecret(namespace, SecretName(apiServiceName), &metav1.DeleteOptions{}) - if err != nil && !k8serrors.IsNotFound(err) { + if err != nil && !apierrors.IsNotFound(err) { return err } } else { @@ -214,13 +214,13 @@ func (i *StrategyDeploymentInstaller) deleteLegacyAPIServiceResources(desc apiSe // Attempt to delete the legacy Role. existingRole, err := i.strategyClient.GetOpClient().GetRole(namespace, SecretName(apiServiceName)) if err != nil { - if !k8serrors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return err } } else if ownerutil.AdoptableLabels(existingRole.GetLabels(), true, i.owner) { logger.Infof("Deleting Role with legacy APIService name %s", existingRole.Name) err = i.strategyClient.GetOpClient().DeleteRole(namespace, SecretName(apiServiceName), &metav1.DeleteOptions{}) - if err != nil && !k8serrors.IsNotFound(err) { + if err != nil && !apierrors.IsNotFound(err) { return err } } else { @@ -230,13 +230,13 @@ func (i *StrategyDeploymentInstaller) deleteLegacyAPIServiceResources(desc apiSe // Attempt to delete the legacy secret RoleBinding. existingRoleBinding, err := i.strategyClient.GetOpClient().GetRoleBinding(namespace, SecretName(apiServiceName)) if err != nil { - if !k8serrors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return err } } else if ownerutil.AdoptableLabels(existingRoleBinding.GetLabels(), true, i.owner) { logger.Infof("Deleting RoleBinding with legacy APIService name %s", existingRoleBinding.Name) err = i.strategyClient.GetOpClient().DeleteRoleBinding(namespace, SecretName(apiServiceName), &metav1.DeleteOptions{}) - if err != nil && !k8serrors.IsNotFound(err) { + if err != nil && !apierrors.IsNotFound(err) { return err } } else { @@ -246,13 +246,13 @@ func (i *StrategyDeploymentInstaller) deleteLegacyAPIServiceResources(desc apiSe // Attempt to delete the legacy ClusterRoleBinding. existingClusterRoleBinding, err := i.strategyClient.GetOpClient().GetClusterRoleBinding(apiServiceName + "-system:auth-delegator") if err != nil { - if !k8serrors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return err } } else if ownerutil.AdoptableLabels(existingClusterRoleBinding.GetLabels(), true, i.owner) { logger.Infof("Deleting ClusterRoleBinding with legacy APIService name %s", existingClusterRoleBinding.Name) err = i.strategyClient.GetOpClient().DeleteClusterRoleBinding(apiServiceName+"-system:auth-delegator", &metav1.DeleteOptions{}) - if err != nil && !k8serrors.IsNotFound(err) { + if err != nil && !apierrors.IsNotFound(err) { return err } } else { @@ -262,13 +262,13 @@ func (i *StrategyDeploymentInstaller) deleteLegacyAPIServiceResources(desc apiSe // Attempt to delete the legacy AuthReadingRoleBinding. existingRoleBinding, err = i.strategyClient.GetOpClient().GetRoleBinding(KubeSystem, apiServiceName+"-auth-reader") if err != nil { - if !k8serrors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return err } } else if ownerutil.AdoptableLabels(existingRoleBinding.GetLabels(), true, i.owner) { logger.Infof("Deleting RoleBinding with legacy APIService name %s", existingRoleBinding.Name) err = i.strategyClient.GetOpClient().DeleteRoleBinding(KubeSystem, apiServiceName+"-auth-reader", &metav1.DeleteOptions{}) - if err != nil && !k8serrors.IsNotFound(err) { + if err != nil && !apierrors.IsNotFound(err) { return err } } else { diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go b/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go index 1021a2d265..77643e9dc0 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/certresources.go @@ -9,7 +9,7 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -246,7 +246,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo // Delete the Service to replace deleteErr := i.strategyClient.GetOpClient().DeleteService(service.GetNamespace(), service.GetName(), &metav1.DeleteOptions{}) - if deleteErr != nil && !k8serrors.IsNotFound(deleteErr) { + if deleteErr != nil && !apierrors.IsNotFound(deleteErr) { return nil, nil, fmt.Errorf("could not delete existing service %s", service.GetName()) } } @@ -315,11 +315,11 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo logger.Warnf("could not update secret %s", secret.GetName()) return nil, nil, err } - } else if k8serrors.IsNotFound(err) { + } else if apierrors.IsNotFound(err) { // Create the secret ownerutil.AddNonBlockingOwner(secret, i.owner) if _, err := i.strategyClient.GetOpClient().CreateSecret(secret); err != nil { - if !k8serrors.IsAlreadyExists(err) { + if !apierrors.IsAlreadyExists(err) { log.Warnf("could not create secret %s: %v", secret.GetName(), err) return nil, nil, err } @@ -360,7 +360,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo logger.Warnf("could not update secret role %s", secretRole.GetName()) return nil, nil, err } - } else if k8serrors.IsNotFound(err) { + } else if apierrors.IsNotFound(err) { // Create the role ownerutil.AddNonBlockingOwner(secretRole, i.owner) _, err = i.strategyClient.GetOpClient().CreateRole(secretRole) @@ -406,7 +406,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo logger.Warnf("could not update secret rolebinding %s", secretRoleBinding.GetName()) return nil, nil, err } - } else if k8serrors.IsNotFound(err) { + } else if apierrors.IsNotFound(err) { // Create the role ownerutil.AddNonBlockingOwner(secretRoleBinding, i.owner) _, err = i.strategyClient.GetOpClient().CreateRoleBinding(secretRoleBinding) @@ -451,7 +451,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo logger.Warnf("could not update auth delegator clusterrolebinding %s", authDelegatorClusterRoleBinding.GetName()) return nil, nil, err } - } else if k8serrors.IsNotFound(err) { + } else if apierrors.IsNotFound(err) { // Create the role. if err := ownerutil.AddOwnerLabels(authDelegatorClusterRoleBinding, i.owner); err != nil { return nil, nil, err @@ -498,7 +498,7 @@ func (i *StrategyDeploymentInstaller) installCertRequirementsForDeployment(deplo logger.Warnf("could not update auth reader role binding %s", authReaderRoleBinding.GetName()) return nil, nil, err } - } else if k8serrors.IsNotFound(err) { + } else if apierrors.IsNotFound(err) { // Create the role. if err := ownerutil.AddOwnerLabels(authReaderRoleBinding, i.owner); err != nil { return nil, nil, err diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/deployment.go b/staging/operator-lifecycle-manager/pkg/controller/install/deployment.go index 61adbb623b..d763c51306 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/deployment.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/deployment.go @@ -7,7 +7,7 @@ import ( log "github.com/sirupsen/logrus" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" k8slabels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/rand" "k8s.io/utils/pointer" @@ -192,7 +192,7 @@ func (i *StrategyDeploymentInstaller) Install(s Strategy) error { } if err := i.installDeployments(updatedStrategy.DeploymentSpecs); err != nil { - if k8serrors.IsForbidden(err) { + if apierrors.IsForbidden(err) { return StrategyError{Reason: StrategyErrInsufficientPermissions, Message: fmt.Sprintf("install strategy failed: %s", err)} } return err diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/rule_checker_test.go b/staging/operator-lifecycle-manager/pkg/controller/install/rule_checker_test.go index d49be53902..4a01abfbca 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/rule_checker_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/rule_checker_test.go @@ -18,12 +18,12 @@ import ( "k8s.io/client-go/tools/cache" apiregistrationfake "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/fake" - v1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient" ) func TestRuleSatisfied(t *testing.T) { - csv := &v1alpha1.ClusterServiceVersion{} + csv := &operatorsv1alpha1.ClusterServiceVersion{} csv.SetName("barista-operator") csv.SetUID(types.UID("barista-operator")) @@ -572,7 +572,7 @@ func TestRuleSatisfied(t *testing.T) { } } -func NewFakeCSVRuleChecker(k8sObjs []runtime.Object, csv *v1alpha1.ClusterServiceVersion, namespace string, stopCh <-chan struct{}) (*CSVRuleChecker, error) { +func NewFakeCSVRuleChecker(k8sObjs []runtime.Object, csv *operatorsv1alpha1.ClusterServiceVersion, namespace string, stopCh <-chan struct{}) (*CSVRuleChecker, error) { // create client fakes opClientFake := operatorclient.NewClient(k8sfake.NewSimpleClientset(k8sObjs...), apiextensionsfake.NewSimpleClientset(), apiregistrationfake.NewSimpleClientset()) diff --git a/staging/operator-lifecycle-manager/pkg/controller/install/status_viewer_test.go b/staging/operator-lifecycle-manager/pkg/controller/install/status_viewer_test.go index d931c1297f..eb4170c1d7 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/install/status_viewer_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/install/status_viewer_test.go @@ -5,24 +5,24 @@ import ( "testing" "github.com/stretchr/testify/assert" - apps "k8s.io/api/apps/v1" - core "k8s.io/api/core/v1" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func TestDeploymentStatusViewerStatus(t *testing.T) { tests := []struct { generation int64 - status apps.DeploymentStatus + status appsv1.DeploymentStatus err error msg string done bool }{ { - status: apps.DeploymentStatus{ - Conditions: []apps.DeploymentCondition{ + status: appsv1.DeploymentStatus{ + Conditions: []appsv1.DeploymentCondition{ { - Type: apps.DeploymentProgressing, + Type: appsv1.DeploymentProgressing, Reason: TimedOutReason, }, }, @@ -31,15 +31,15 @@ func TestDeploymentStatusViewerStatus(t *testing.T) { done: false, }, { - status: apps.DeploymentStatus{ - Conditions: []apps.DeploymentCondition{ + status: appsv1.DeploymentStatus{ + Conditions: []appsv1.DeploymentCondition{ { - Type: apps.DeploymentProgressing, + Type: appsv1.DeploymentProgressing, Reason: "NotTimedOut", }, { - Type: apps.DeploymentAvailable, - Status: core.ConditionTrue, + Type: appsv1.DeploymentAvailable, + Status: corev1.ConditionTrue, }, }, }, @@ -48,14 +48,14 @@ func TestDeploymentStatusViewerStatus(t *testing.T) { }, { generation: 1, - status: apps.DeploymentStatus{ + status: appsv1.DeploymentStatus{ ObservedGeneration: 0, }, msg: "waiting for spec update of deployment \"foo\" to be observed...", done: false, }, { - status: apps.DeploymentStatus{ + status: appsv1.DeploymentStatus{ Replicas: 5, UpdatedReplicas: 3, }, @@ -63,16 +63,16 @@ func TestDeploymentStatusViewerStatus(t *testing.T) { done: false, }, { - status: apps.DeploymentStatus{}, - msg: fmt.Sprintf("deployment \"foo\" not available: missing condition %q", apps.DeploymentAvailable), + status: appsv1.DeploymentStatus{}, + msg: fmt.Sprintf("deployment \"foo\" not available: missing condition %q", appsv1.DeploymentAvailable), done: false, }, { - status: apps.DeploymentStatus{ - Conditions: []apps.DeploymentCondition{ + status: appsv1.DeploymentStatus{ + Conditions: []appsv1.DeploymentCondition{ { - Type: apps.DeploymentAvailable, - Status: core.ConditionFalse, + Type: appsv1.DeploymentAvailable, + Status: corev1.ConditionFalse, Message: "test message", }, }, @@ -81,11 +81,11 @@ func TestDeploymentStatusViewerStatus(t *testing.T) { done: false, }, { - status: apps.DeploymentStatus{ - Conditions: []apps.DeploymentCondition{ + status: appsv1.DeploymentStatus{ + Conditions: []appsv1.DeploymentCondition{ { - Type: apps.DeploymentAvailable, - Status: core.ConditionUnknown, + Type: appsv1.DeploymentAvailable, + Status: corev1.ConditionUnknown, Message: "test message", }, }, @@ -94,11 +94,11 @@ func TestDeploymentStatusViewerStatus(t *testing.T) { done: false, }, { - status: apps.DeploymentStatus{ - Conditions: []apps.DeploymentCondition{ + status: appsv1.DeploymentStatus{ + Conditions: []appsv1.DeploymentCondition{ { - Type: apps.DeploymentAvailable, - Status: core.ConditionTrue, + Type: appsv1.DeploymentAvailable, + Status: corev1.ConditionTrue, }, }, }, @@ -109,7 +109,7 @@ func TestDeploymentStatusViewerStatus(t *testing.T) { for i, test := range tests { t.Run(fmt.Sprintf("%d", i+1), func(t *testing.T) { - d := &apps.Deployment{ + d := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Namespace: "bar", Name: "foo", diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go index 71ab352dfd..703d76d284 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/operator.go @@ -21,7 +21,7 @@ import ( apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" "k8s.io/apiextensions-apiserver/pkg/apiserver/validation" extinf "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" @@ -629,7 +629,7 @@ func (o *Operator) syncConfigMap(logger *logrus.Entry, in *v1alpha1.CatalogSourc // Get the catalog source's config map configMap, err := o.lister.CoreV1().ConfigMapLister().ConfigMaps(in.GetNamespace()).Get(in.Spec.ConfigMap) // Attempt to look up the CM via api call if there is a cache miss - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { configMap, err = o.opClient.KubernetesInterface().CoreV1().ConfigMaps(in.GetNamespace()).Get(context.TODO(), in.Spec.ConfigMap, metav1.GetOptions{}) // Found cm in the cluster, add managed label to configmap if err == nil { @@ -2322,7 +2322,7 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error { } return nil }(i, step); err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { // Check for APIVersions present in the installplan steps that are not available on the server. // The check is made via discovery per step in the plan. Transient communication failures to the api-server are handled by the plan retry logic. notFoundErr := discoveryQuerier.WithStepResource(step.Resource).QueryForGVK() diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step.go index a6a80bfaff..54abd56bf9 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step.go @@ -10,7 +10,7 @@ import ( apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1" apiextensionsv1client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1" apiextensionsv1beta1client "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1beta1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/dynamic" "k8s.io/client-go/util/retry" @@ -100,7 +100,7 @@ func (b *builder) NewCRDV1Step(client apiextensionsv1client.ApiextensionsV1Inter case v1alpha1.StepStatusWaitingForAPI: crd, err := client.CustomResourceDefinitions().Get(context.TODO(), step.Resource.Name, metav1.GetOptions{}) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return v1alpha1.StepStatusNotPresent, nil } return v1alpha1.StepStatusNotPresent, errors.Wrapf(err, "error finding the %s CRD", crd.Name) @@ -130,7 +130,7 @@ func (b *builder) NewCRDV1Step(client apiextensionsv1client.ApiextensionsV1Inter setInstalledAlongsideAnnotation(b.annotator, crd, b.plan.GetNamespace(), step.Resolving, b.csvLister, crd) _, createError := client.CustomResourceDefinitions().Create(context.TODO(), crd, metav1.CreateOptions{}) - if k8serrors.IsAlreadyExists(createError) { + if apierrors.IsAlreadyExists(createError) { err := retry.RetryOnConflict(retry.DefaultRetry, func() error { currentCRD, _ := client.CustomResourceDefinitions().Get(context.TODO(), crd.GetName(), metav1.GetOptions{}) crd.SetResourceVersion(currentCRD.GetResourceVersion()) @@ -183,7 +183,7 @@ func (b *builder) NewCRDV1Beta1Step(client apiextensionsv1beta1client.Apiextensi case v1alpha1.StepStatusWaitingForAPI: crd, err := client.CustomResourceDefinitions().Get(context.TODO(), step.Resource.Name, metav1.GetOptions{}) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return v1alpha1.StepStatusNotPresent, nil } return v1alpha1.StepStatusNotPresent, fmt.Errorf("error finding the %q CRD: %w", crd.Name, err) @@ -213,7 +213,7 @@ func (b *builder) NewCRDV1Beta1Step(client apiextensionsv1beta1client.Apiextensi setInstalledAlongsideAnnotation(b.annotator, crd, b.plan.GetNamespace(), step.Resolving, b.csvLister, crd) _, createError := client.CustomResourceDefinitions().Create(context.TODO(), crd, metav1.CreateOptions{}) - if k8serrors.IsAlreadyExists(createError) { + if apierrors.IsAlreadyExists(createError) { err := retry.RetryOnConflict(retry.DefaultRetry, func() error { currentCRD, _ := client.CustomResourceDefinitions().Get(context.TODO(), crd.GetName(), metav1.GetOptions{}) crd.SetResourceVersion(currentCRD.GetResourceVersion()) @@ -270,7 +270,7 @@ func setInstalledAlongsideAnnotation(a alongside.Annotator, dst metav1.Object, n continue } - if csv, err := lister.ClusterServiceVersions(nn.Namespace).Get(nn.Name); k8serrors.IsNotFound(err) { + if csv, err := lister.ClusterServiceVersions(nn.Namespace).Get(nn.Name); apierrors.IsNotFound(err) { continue } else if err == nil && csv.IsCopied() { continue diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step_ensurer.go b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step_ensurer.go index 6ce7e505da..91c309f97a 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step_ensurer.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/catalog/step_ensurer.go @@ -8,7 +8,7 @@ import ( corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" apiequality "k8s.io/apimachinery/pkg/api/equality" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/client-go/dynamic" @@ -43,7 +43,7 @@ func (o *StepEnsurer) EnsureClusterServiceVersion(csv *v1alpha1.ClusterServiceVe return } - if !k8serrors.IsAlreadyExists(createErr) { + if !apierrors.IsAlreadyExists(createErr) { err = errorwrap.Wrapf(createErr, "error creating csv %s", csv.GetName()) return } @@ -60,7 +60,7 @@ func (o *StepEnsurer) EnsureSubscription(subscription *v1alpha1.Subscription) (s return } - if !k8serrors.IsAlreadyExists(createErr) { + if !apierrors.IsAlreadyExists(createErr) { err = errorwrap.Wrapf(createErr, "error creating subscription %s", subscription.GetName()) return } @@ -74,7 +74,7 @@ func (o *StepEnsurer) EnsureSubscription(subscription *v1alpha1.Subscription) (s func (o *StepEnsurer) EnsureSecret(operatorNamespace, planNamespace, name string) (status v1alpha1.StepStatus, err error) { secret, getError := o.kubeClient.KubernetesInterface().CoreV1().Secrets(operatorNamespace).Get(context.TODO(), name, metav1.GetOptions{}) if getError != nil { - if k8serrors.IsNotFound(getError) { + if apierrors.IsNotFound(getError) { err = fmt.Errorf("secret %s does not exist - %v", name, getError) return } @@ -97,7 +97,7 @@ func (o *StepEnsurer) EnsureSecret(operatorNamespace, planNamespace, name string } if _, createError := o.kubeClient.KubernetesInterface().CoreV1().Secrets(planNamespace).Create(context.TODO(), newSecret, metav1.CreateOptions{}); createError != nil { - if k8serrors.IsAlreadyExists(createError) { + if apierrors.IsAlreadyExists(createError) { status = v1alpha1.StepStatusPresent return } @@ -118,7 +118,7 @@ func (o *StepEnsurer) EnsureBundleSecret(namespace string, secret *corev1.Secret return } - if !k8serrors.IsAlreadyExists(createErr) { + if !apierrors.IsAlreadyExists(createErr) { err = errorwrap.Wrapf(createErr, "error updating secret: %s", secret.GetName()) return } @@ -142,7 +142,7 @@ func (o *StepEnsurer) EnsureServiceAccount(namespace string, sa *corev1.ServiceA return } - if !k8serrors.IsAlreadyExists(createErr) { + if !apierrors.IsAlreadyExists(createErr) { err = errorwrap.Wrapf(createErr, "error creating service account: %s", sa.GetName()) return } @@ -180,7 +180,7 @@ func (o *StepEnsurer) EnsureService(namespace string, service *corev1.Service) ( return } - if !k8serrors.IsAlreadyExists(createErr) { + if !apierrors.IsAlreadyExists(createErr) { err = errorwrap.Wrapf(createErr, "error updating service: %s", service.GetName()) return } @@ -203,7 +203,7 @@ func (o *StepEnsurer) EnsureClusterRole(cr *rbacv1.ClusterRole, step *v1alpha1.S return } - if !k8serrors.IsAlreadyExists(createErr) { + if !apierrors.IsAlreadyExists(createErr) { err = errorwrap.Wrapf(createErr, "error creating clusterrole %s", cr.GetName()) return } @@ -230,7 +230,7 @@ func (o *StepEnsurer) EnsureClusterRoleBinding(crb *rbacv1.ClusterRoleBinding, s return } - if !k8serrors.IsAlreadyExists(createErr) { + if !apierrors.IsAlreadyExists(createErr) { err = errorwrap.Wrapf(createErr, "error creating clusterrolebinding %s", crb.GetName()) return } @@ -257,7 +257,7 @@ func (o *StepEnsurer) EnsureRole(namespace string, role *rbacv1.Role) (status v1 return } - if !k8serrors.IsAlreadyExists(createErr) { + if !apierrors.IsAlreadyExists(createErr) { err = errorwrap.Wrapf(createErr, "error creating role %s", role.GetName()) return } @@ -281,7 +281,7 @@ func (o *StepEnsurer) EnsureRoleBinding(namespace string, rb *rbacv1.RoleBinding return } - if !k8serrors.IsAlreadyExists(createErr) { + if !apierrors.IsAlreadyExists(createErr) { err = errorwrap.Wrapf(createErr, "error creating rolebinding %s", rb.GetName()) return } @@ -304,7 +304,7 @@ func (o *StepEnsurer) EnsureUnstructuredObject(client dynamic.ResourceInterface, return } - if !k8serrors.IsAlreadyExists(createErr) { + if !apierrors.IsAlreadyExists(createErr) { err = errorwrap.Wrapf(createErr, "error creating unstructured object %s", obj.GetName()) return } @@ -336,7 +336,7 @@ func (o *StepEnsurer) EnsureConfigMap(namespace string, configmap *corev1.Config return } - if !k8serrors.IsAlreadyExists(createErr) { + if !apierrors.IsAlreadyExists(createErr) { err = errorwrap.Wrapf(createErr, "error updating configmap: %s", configmap.GetName()) return } diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/apiservices.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/apiservices.go index 79e79179af..d3524cd8e7 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/apiservices.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/apiservices.go @@ -7,7 +7,7 @@ import ( log "github.com/sirupsen/logrus" appsv1 "k8s.io/api/apps/v1" rbacv1 "k8s.io/api/rbac/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" utilerrors "k8s.io/apimachinery/pkg/util/errors" @@ -148,7 +148,7 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion, // Ensure the existing Deployment has a matching CA hash annotation deployment, err := a.lister.AppsV1().DeploymentLister().Deployments(csv.GetNamespace()).Get(desc.DeploymentName) - if k8serrors.IsNotFound(err) || err != nil { + if apierrors.IsNotFound(err) || err != nil { logger.WithField("deployment", desc.DeploymentName).Warnf("expected Deployment could not be retrieved") errs = append(errs, err) continue @@ -227,7 +227,7 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion, func (a *Operator) areAPIServicesAvailable(csv *v1alpha1.ClusterServiceVersion) (bool, error) { for _, desc := range csv.Spec.APIServiceDefinitions.Owned { apiService, err := a.lister.APIRegistrationV1().APIServiceLister().Get(desc.GetName()) - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return false, nil } @@ -410,7 +410,7 @@ func (a *Operator) cleanUpRemovedWebhooks(csv *v1alpha1.ClusterServiceVersion) e } if _, ok := csvWebhookGenerateNames[webhookGenerateNameLabel]; !ok { err = a.opClient.KubernetesInterface().AdmissionregistrationV1().ValidatingWebhookConfigurations().Delete(context.TODO(), webhook.Name, metav1.DeleteOptions{}) - if err != nil && k8serrors.IsNotFound(err) { + if err != nil && apierrors.IsNotFound(err) { return err } } @@ -428,7 +428,7 @@ func (a *Operator) cleanUpRemovedWebhooks(csv *v1alpha1.ClusterServiceVersion) e } if _, ok := csvWebhookGenerateNames[webhookGenerateNameLabel]; !ok { err = a.opClient.KubernetesInterface().AdmissionregistrationV1().MutatingWebhookConfigurations().Delete(context.TODO(), webhook.Name, metav1.DeleteOptions{}) - if err != nil && k8serrors.IsNotFound(err) { + if err != nil && apierrors.IsNotFound(err) { return err } } diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/groups.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/groups.go index 90481c5f4a..b1844d5078 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/groups.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/groups.go @@ -3,7 +3,7 @@ package olm import ( "strings" - v1 "github.com/operator-framework/api/pkg/operators/v1" + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/cache" ) @@ -106,14 +106,14 @@ type OperatorGroup struct { providedAPIs cache.APISet } -func NewOperatorGroup(group *v1.OperatorGroup) *OperatorGroup { +func NewOperatorGroup(group *operatorsv1.OperatorGroup) *OperatorGroup { // Add operatorgroup namespace if not NamespaceAll namespaces := group.Status.Namespaces if len(namespaces) >= 1 && namespaces[0] != "" { namespaces = append(namespaces, group.GetNamespace()) } // TODO: Sanitize OperatorGroup if len(namespaces) > 1 and contains "" - gvksStr := group.GetAnnotations()[v1.OperatorGroupProvidedAPIsAnnotationKey] + gvksStr := group.GetAnnotations()[operatorsv1.OperatorGroupProvidedAPIsAnnotationKey] return &OperatorGroup{ namespace: group.GetNamespace(), @@ -123,7 +123,7 @@ func NewOperatorGroup(group *v1.OperatorGroup) *OperatorGroup { } } -func NewOperatorGroupSurfaces(groups ...v1.OperatorGroup) []OperatorGroupSurface { +func NewOperatorGroupSurfaces(groups ...operatorsv1.OperatorGroup) []OperatorGroupSurface { operatorGroups := make([]OperatorGroupSurface, len(groups)) for i, group := range groups { operatorGroups[i] = NewOperatorGroup(&group) diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/groups_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/groups_test.go index 0f986c041e..d3f086407d 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/groups_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/groups_test.go @@ -4,24 +4,24 @@ import ( "strings" "testing" + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" opregistry "github.com/operator-framework/operator-registry/pkg/registry" "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - v1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/cache" ) -func buildAPIOperatorGroup(namespace, name string, targets []string, gvks []string) *v1.OperatorGroup { - return &v1.OperatorGroup{ +func buildAPIOperatorGroup(namespace, name string, targets []string, gvks []string) *operatorsv1.OperatorGroup { + return &operatorsv1.OperatorGroup{ ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, Name: name, Annotations: map[string]string{ - v1.OperatorGroupProvidedAPIsAnnotationKey: strings.Join(gvks, ","), + operatorsv1.OperatorGroupProvidedAPIsAnnotationKey: strings.Join(gvks, ","), }, }, - Status: v1.OperatorGroupStatus{ + Status: operatorsv1.OperatorGroupStatus{ Namespaces: targets, }, } @@ -29,7 +29,7 @@ func buildAPIOperatorGroup(namespace, name string, targets []string, gvks []stri func TestNewOperatorGroup(t *testing.T) { tests := []struct { name string - in *v1.OperatorGroup + in *operatorsv1.OperatorGroup want *OperatorGroup }{ { diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go index 180d0212a0..7efa2746d6 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator.go @@ -7,13 +7,12 @@ import ( "strings" "time" - v1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/sirupsen/logrus" admissionregistrationv1 "k8s.io/api/admissionregistration/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" extinf "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -30,6 +29,7 @@ import ( apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" kagg "k8s.io/kube-aggregator/pkg/client/informers/externalversions" + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/informers/externalversions" @@ -633,14 +633,14 @@ func (a *Operator) syncAPIService(obj interface{}) (syncError error) { if name, ns, ok := ownerutil.GetOwnerByKindLabel(apiService, v1alpha1.ClusterServiceVersionKind); ok { _, err := a.lister.CoreV1().NamespaceLister().Get(ns) - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { logger.Debug("Deleting api service since owning namespace is not found") syncError = a.opClient.DeleteAPIService(apiService.GetName(), &metav1.DeleteOptions{}) return } _, err = a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(ns).Get(name) - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { logger.Debug("Deleting api service since owning CSV is not found") syncError = a.opClient.DeleteAPIService(apiService.GetName(), &metav1.DeleteOptions{}) return @@ -711,7 +711,7 @@ func (a *Operator) syncGCObject(obj interface{}) (syncError error) { logger.Debugf("CSV still present, must wait until it is deleted (owners=%v/%v)", ns, name) syncError = fmt.Errorf("cleanup must wait") return - } else if !k8serrors.IsNotFound(err) { + } else if !apierrors.IsNotFound(err) { syncError = err return } @@ -729,7 +729,7 @@ func (a *Operator) syncGCObject(obj interface{}) (syncError error) { logger.Debugf("CSV still present, must wait until it is deleted (owners=%v)", name) syncError = fmt.Errorf("cleanup must wait") return - } else if !k8serrors.IsNotFound(err) { + } else if !apierrors.IsNotFound(err) { syncError = err return } @@ -747,7 +747,7 @@ func (a *Operator) syncGCObject(obj interface{}) (syncError error) { logger.Debugf("CSV still present, must wait until it is deleted (owners=%v)", name) syncError = fmt.Errorf("cleanup must wait") return - } else if !k8serrors.IsNotFound(err) { + } else if !apierrors.IsNotFound(err) { logger.Infof("error CSV retrieval error") syncError = err return @@ -766,7 +766,7 @@ func (a *Operator) syncGCObject(obj interface{}) (syncError error) { logger.Debugf("CSV still present, must wait until it is deleted (owners=%v)", name) syncError = fmt.Errorf("cleanup must wait") return - } else if !k8serrors.IsNotFound(err) { + } else if !apierrors.IsNotFound(err) { logger.Infof("Error CSV retrieval error") syncError = err return @@ -804,7 +804,7 @@ func (a *Operator) syncObject(obj interface{}) (syncError error) { logger.Error("unexpected owner label retrieval failure") } _, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(ns).Get(name) - if !k8serrors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { logger.Debug("requeueing owner csvs from owner label") a.requeueOwnerCSVs(metaObj) } else { @@ -903,7 +903,7 @@ func (a *Operator) syncNamespace(obj interface{}) error { // Remove existing OperatorGroup labels for label := range namespace.GetLabels() { - if v1.IsOperatorGroupLabel(label) { + if operatorsv1.IsOperatorGroupLabel(label) { delete(namespace.Labels, label) } } @@ -993,19 +993,19 @@ func (a *Operator) handleClusterServiceVersionDeletion(obj interface{}) { } }(*clusterServiceVersion) - targetNamespaces, ok := clusterServiceVersion.Annotations[v1.OperatorGroupTargetsAnnotationKey] + targetNamespaces, ok := clusterServiceVersion.Annotations[operatorsv1.OperatorGroupTargetsAnnotationKey] if !ok { logger.Debug("missing target namespaces annotation on csv") return } - operatorNamespace, ok := clusterServiceVersion.Annotations[v1.OperatorGroupNamespaceAnnotationKey] + operatorNamespace, ok := clusterServiceVersion.Annotations[operatorsv1.OperatorGroupNamespaceAnnotationKey] if !ok { logger.Debug("missing operator namespace annotation on csv") return } - if _, ok = clusterServiceVersion.Annotations[v1.OperatorGroupAnnotationKey]; !ok { + if _, ok = clusterServiceVersion.Annotations[operatorsv1.OperatorGroupAnnotationKey]; !ok { logger.Debug("missing operatorgroup name annotation on csv") return } @@ -1036,7 +1036,7 @@ func (a *Operator) handleClusterServiceVersionDeletion(obj interface{}) { for _, desc := range clusterServiceVersion.Spec.APIServiceDefinitions.Owned { apiServiceName := fmt.Sprintf("%s.%s", desc.Version, desc.Group) fetched, err := a.lister.APIRegistrationV1().APIServiceLister().Get(apiServiceName) - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { continue } if err != nil { @@ -1113,7 +1113,7 @@ func (a *Operator) removeDanglingChildCSVs(csv *v1alpha1.ClusterServiceVersion) return nil } - operatorNamespace, ok := csv.Annotations[v1.OperatorGroupNamespaceAnnotationKey] + operatorNamespace, ok := csv.Annotations[operatorsv1.OperatorGroupNamespaceAnnotationKey] if !ok { logger.Debug("missing operator namespace annotation on copied CSV") return a.deleteChild(csv, logger) @@ -1121,7 +1121,7 @@ func (a *Operator) removeDanglingChildCSVs(csv *v1alpha1.ClusterServiceVersion) logger = logger.WithField("parentNamespace", operatorNamespace) parent, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(operatorNamespace).Get(csv.GetName()) - if k8serrors.IsNotFound(err) || k8serrors.IsGone(err) || parent == nil { + if apierrors.IsNotFound(err) || apierrors.IsGone(err) || parent == nil { logger.Debug("deleting copied CSV since parent is missing") return a.deleteChild(csv, logger) } @@ -1132,8 +1132,8 @@ func (a *Operator) removeDanglingChildCSVs(csv *v1alpha1.ClusterServiceVersion) } if annotations := parent.GetAnnotations(); annotations != nil { - if !NewNamespaceSetFromString(annotations[v1.OperatorGroupTargetsAnnotationKey]).Contains(csv.GetNamespace()) { - logger.WithField("parentTargets", annotations[v1.OperatorGroupTargetsAnnotationKey]). + if !NewNamespaceSetFromString(annotations[operatorsv1.OperatorGroupTargetsAnnotationKey]).Contains(csv.GetNamespace()) { + logger.WithField("parentTargets", annotations[operatorsv1.OperatorGroupTargetsAnnotationKey]). Debug("deleting copied CSV since parent no longer lists this as a target namespace") return a.deleteChild(csv, logger) } @@ -1230,13 +1230,13 @@ func (a *Operator) syncClusterServiceVersion(obj interface{}) (syncError error) return } -func (a *Operator) allNamespaceOperatorGroups() ([]*v1.OperatorGroup, error) { +func (a *Operator) allNamespaceOperatorGroups() ([]*operatorsv1.OperatorGroup, error) { operatorGroups, err := a.lister.OperatorsV1().OperatorGroupLister().List(labels.Everything()) if err != nil { return nil, err } - result := []*v1.OperatorGroup{} + result := []*operatorsv1.OperatorGroup{} for _, operatorGroup := range operatorGroups { if NewNamespaceSet(operatorGroup.Status.Namespaces).IsAllNamespaces() { result = append(result, operatorGroup.DeepCopy()) @@ -1247,7 +1247,7 @@ func (a *Operator) allNamespaceOperatorGroups() ([]*v1.OperatorGroup, error) { func (a *Operator) syncOLMConfig(obj interface{}) (syncError error) { a.logger.Debug("Processing olmConfig") - olmConfig, ok := obj.(*v1.OLMConfig) + olmConfig, ok := obj.(*operatorsv1.OLMConfig) if !ok { return fmt.Errorf("casting OLMConfig failed") } @@ -1325,7 +1325,7 @@ func isStatusConditionPresentAndAreTypeReasonMessageStatusEqual(conditions []met func getCopiedCSVsCondition(isDisabled, csvIsRequeued bool) metav1.Condition { condition := metav1.Condition{ - Type: v1.DisabledCopiedCSVsConditionType, + Type: operatorsv1.DisabledCopiedCSVsConditionType, LastTransitionTime: metav1.Now(), Status: metav1.ConditionFalse, } @@ -1359,7 +1359,7 @@ func (a *Operator) syncCopyCSV(obj interface{}) (syncError error) { } olmConfig, err := a.client.OperatorsV1().OLMConfigs().Get(context.TODO(), "cluster", metav1.GetOptions{}) - if err != nil && !k8serrors.IsNotFound(err) { + if err != nil && !apierrors.IsNotFound(err) { return err } @@ -1423,7 +1423,7 @@ func (a *Operator) syncCopyCSV(obj interface{}) (syncError error) { for _, copiedCSV := range copiedCSVs { err := a.client.OperatorsV1alpha1().ClusterServiceVersions(copiedCSV.Namespace).Delete(context.TODO(), copiedCSV.Name, metav1.DeleteOptions{}) - if err != nil && !k8serrors.IsNotFound(err) { + if err != nil && !apierrors.IsNotFound(err) { return err } } @@ -1451,7 +1451,7 @@ func (a *Operator) copiedCSVsAreEnabled() (bool, error) { olmConfig, err := a.client.OperatorsV1().OLMConfigs().Get(context.TODO(), "cluster", metav1.GetOptions{}) if err != nil { // Default to true if olmConfig singleton cannot be found - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return true, nil } // If there was an error that wasn't an IsNotFound, return the error @@ -1477,7 +1477,7 @@ func (a *Operator) getCopiedCSVDisabledEventsForCSV(csv *v1alpha1.ClusterService if event.InvolvedObject.Namespace == csv.GetNamespace() && event.InvolvedObject.Name == csv.GetName() && event.InvolvedObject.UID == csv.GetUID() && - event.Reason == v1.DisabledCopiedCSVsConditionType { + event.Reason == operatorsv1.DisabledCopiedCSVsConditionType { result = append(result, *event.DeepCopy()) } } @@ -1498,7 +1498,7 @@ func (a *Operator) deleteCSVCopyingDisabledEvent(csv *v1alpha1.ClusterServiceVer func (a *Operator) deleteEvents(events []corev1.Event) error { for _, event := range events { err := a.opClient.KubernetesInterface().EventsV1().Events(event.GetNamespace()).Delete(context.TODO(), event.GetName(), metav1.DeleteOptions{}) - if err != nil && !k8serrors.IsNotFound(err) { + if err != nil && !apierrors.IsNotFound(err) { return err } } @@ -1522,7 +1522,7 @@ func (a *Operator) createCSVCopyingDisabledEvent(csv *v1alpha1.ClusterServiceVer } } - a.recorder.Eventf(csv, corev1.EventTypeWarning, v1.DisabledCopiedCSVsConditionType, "CSV copying disabled for %s/%s", csv.GetNamespace(), csv.GetName()) + a.recorder.Eventf(csv, corev1.EventTypeWarning, operatorsv1.DisabledCopiedCSVsConditionType, "CSV copying disabled for %s/%s", csv.GetNamespace(), csv.GetName()) return nil } @@ -1541,7 +1541,7 @@ func (a *Operator) syncGcCsv(obj interface{}) (syncError error) { } // operatorGroupFromAnnotations returns the OperatorGroup for the CSV only if the CSV is active one in the group -func (a *Operator) operatorGroupFromAnnotations(logger *logrus.Entry, csv *v1alpha1.ClusterServiceVersion) *v1.OperatorGroup { +func (a *Operator) operatorGroupFromAnnotations(logger *logrus.Entry, csv *v1alpha1.ClusterServiceVersion) *operatorsv1.OperatorGroup { annotations := csv.GetAnnotations() // Not part of a group yet @@ -1551,12 +1551,12 @@ func (a *Operator) operatorGroupFromAnnotations(logger *logrus.Entry, csv *v1alp } // Not in the OperatorGroup namespace - if annotations[v1.OperatorGroupNamespaceAnnotationKey] != csv.GetNamespace() { + if annotations[operatorsv1.OperatorGroupNamespaceAnnotationKey] != csv.GetNamespace() { logger.Info("not in operatorgroup namespace") return nil } - operatorGroupName, ok := annotations[v1.OperatorGroupAnnotationKey] + operatorGroupName, ok := annotations[operatorsv1.OperatorGroupAnnotationKey] // No OperatorGroup annotation if !ok { @@ -1573,7 +1573,7 @@ func (a *Operator) operatorGroupFromAnnotations(logger *logrus.Entry, csv *v1alp return nil } - targets, ok := annotations[v1.OperatorGroupTargetsAnnotationKey] + targets, ok := annotations[operatorsv1.OperatorGroupTargetsAnnotationKey] // No target annotation if !ok { @@ -1590,7 +1590,7 @@ func (a *Operator) operatorGroupFromAnnotations(logger *logrus.Entry, csv *v1alp return operatorGroup.DeepCopy() } -func (a *Operator) operatorGroupForCSV(csv *v1alpha1.ClusterServiceVersion, logger *logrus.Entry) (*v1.OperatorGroup, error) { +func (a *Operator) operatorGroupForCSV(csv *v1alpha1.ClusterServiceVersion, logger *logrus.Entry) (*operatorsv1.OperatorGroup, error) { now := a.now() // Attempt to associate an OperatorGroup with the CSV. @@ -1599,7 +1599,7 @@ func (a *Operator) operatorGroupForCSV(csv *v1alpha1.ClusterServiceVersion, logg logger.Errorf("error occurred while attempting to associate csv with operatorgroup") return nil, err } - var operatorGroup *v1.OperatorGroup + var operatorGroup *operatorsv1.OperatorGroup switch len(operatorGroups) { case 0: @@ -1696,7 +1696,7 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v } // Check if the CSV supports its operatorgroup's selected namespaces - targets, ok := out.GetAnnotations()[v1.OperatorGroupTargetsAnnotationKey] + targets, ok := out.GetAnnotations()[operatorsv1.OperatorGroupTargetsAnnotationKey] if ok { namespaces := strings.Split(targets, ",") @@ -1717,7 +1717,7 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v logger.WithError(err).Warn("failed to list operatorgroups") return } - otherGroups := make([]v1.OperatorGroup, 0, len(allGroups)) + otherGroups := make([]operatorsv1.OperatorGroup, 0, len(allGroups)) for _, g := range allGroups { if g.GetName() != operatorGroup.GetName() || g.GetNamespace() != operatorGroup.GetNamespace() { otherGroups = append(otherGroups, *g) @@ -1753,16 +1753,16 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v if unionedAnnotations == nil { unionedAnnotations = make(map[string]string) } - if unionedAnnotations[v1.OperatorGroupProvidedAPIsAnnotationKey] == union.String() { + if unionedAnnotations[operatorsv1.OperatorGroupProvidedAPIsAnnotationKey] == union.String() { // resolver may think apis need adding with invalid input, so continue when there's no work // to be done so that the CSV can progress far enough to get requirements checked a.logger.Debug("operator group annotations up to date, continuing") break } - unionedAnnotations[v1.OperatorGroupProvidedAPIsAnnotationKey] = union.String() + unionedAnnotations[operatorsv1.OperatorGroupProvidedAPIsAnnotationKey] = union.String() operatorGroup.SetAnnotations(unionedAnnotations) - if _, err := a.client.OperatorsV1().OperatorGroups(operatorGroup.GetNamespace()).Update(context.TODO(), operatorGroup, metav1.UpdateOptions{}); err != nil && !k8serrors.IsNotFound(err) { - syncError = fmt.Errorf("could not update operatorgroups %s annotation: %v", v1.OperatorGroupProvidedAPIsAnnotationKey, err) + if _, err := a.client.OperatorsV1().OperatorGroups(operatorGroup.GetNamespace()).Update(context.TODO(), operatorGroup, metav1.UpdateOptions{}); err != nil && !apierrors.IsNotFound(err) { + syncError = fmt.Errorf("could not update operatorgroups %s annotation: %v", operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, err) } if err := a.csvQueueSet.Requeue(out.GetNamespace(), out.GetName()); err != nil { a.logger.WithError(err).Warn("unable to requeue") @@ -1773,10 +1773,10 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v logger.WithField("apis", providedAPIs).Debug("removing csv provided apis from operatorgroup") difference := groupSurface.ProvidedAPIs().Difference(providedAPIs) if diffedAnnotations := operatorGroup.GetAnnotations(); diffedAnnotations != nil { - diffedAnnotations[v1.OperatorGroupProvidedAPIsAnnotationKey] = difference.String() + diffedAnnotations[operatorsv1.OperatorGroupProvidedAPIsAnnotationKey] = difference.String() operatorGroup.SetAnnotations(diffedAnnotations) - if _, err := a.client.OperatorsV1().OperatorGroups(operatorGroup.GetNamespace()).Update(context.TODO(), operatorGroup, metav1.UpdateOptions{}); err != nil && !k8serrors.IsNotFound(err) { - syncError = fmt.Errorf("could not update operatorgroups %s annotation: %v", v1.OperatorGroupProvidedAPIsAnnotationKey, err) + if _, err := a.client.OperatorsV1().OperatorGroups(operatorGroup.GetNamespace()).Update(context.TODO(), operatorGroup, metav1.UpdateOptions{}); err != nil && !apierrors.IsNotFound(err) { + syncError = fmt.Errorf("could not update operatorgroups %s annotation: %v", operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, err) } } if err := a.csvQueueSet.Requeue(out.GetNamespace(), out.GetName()); err != nil { @@ -1917,7 +1917,7 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v } if installErr := a.updateInstallStatus(out, installer, strategy, v1alpha1.CSVPhaseInstalling, v1alpha1.CSVReasonWaiting); installErr != nil { // Re-sync if kube-apiserver was unavailable - if k8serrors.IsServiceUnavailable(installErr) { + if apierrors.IsServiceUnavailable(installErr) { logger.WithError(installErr).Info("could not update install status") syncError = installErr return @@ -1979,7 +1979,7 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v } if installErr := a.updateInstallStatus(out, installer, strategy, v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonComponentUnhealthy); installErr != nil { // Re-sync if kube-apiserver was unavailable - if k8serrors.IsServiceUnavailable(installErr) { + if apierrors.IsServiceUnavailable(installErr) { logger.WithError(installErr).Info("could not update install status") syncError = installErr return @@ -2067,7 +2067,7 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v } if installErr := a.updateInstallStatus(out, installer, strategy, v1alpha1.CSVPhasePending, v1alpha1.CSVReasonNeedsReinstall); installErr != nil { // Re-sync if kube-apiserver was unavailable - if k8serrors.IsServiceUnavailable(installErr) { + if apierrors.IsServiceUnavailable(installErr) { logger.WithError(installErr).Info("could not update install status") syncError = installErr return @@ -2150,7 +2150,7 @@ func (a *Operator) updateInstallStatus(csv *v1alpha1.ClusterServiceVersion, inst return nil } - if err := findFirstError(k8serrors.IsServiceUnavailable, strategyErr, apiServiceErr, webhookErr); err != nil { + if err := findFirstError(apierrors.IsServiceUnavailable, strategyErr, apiServiceErr, webhookErr); err != nil { return err } @@ -2327,7 +2327,7 @@ func (a *Operator) apiServiceOwnerConflicts(csv *v1alpha1.ClusterServiceVersion) for _, desc := range csv.GetOwnedAPIServiceDescriptions() { // Check if the APIService exists apiService, err := a.lister.APIRegistrationV1().APIServiceLister().Get(desc.GetName()) - if err != nil && !k8serrors.IsNotFound(err) && !k8serrors.IsGone(err) { + if err != nil && !apierrors.IsNotFound(err) && !apierrors.IsGone(err) { return err } @@ -2418,7 +2418,7 @@ func (a *Operator) requeueOwnerCSVs(ownee metav1.Object) { if len(owners) > 0 && ownee.GetNamespace() != metav1.NamespaceAll { for _, ownerCSV := range owners { _, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(ownee.GetNamespace()).Get(ownerCSV.Name) - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { logger.Debugf("skipping requeue since CSV %v is not in cache", ownerCSV.Name) continue } @@ -2434,7 +2434,7 @@ func (a *Operator) requeueOwnerCSVs(ownee metav1.Object) { // Requeue owners based on labels if name, ns, ok := ownerutil.GetOwnerByKindLabel(ownee, v1alpha1.ClusterServiceVersionKind); ok { _, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(ns).Get(name) - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { logger.Debugf("skipping requeue since CSV %v is not in cache", name) return } diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator_test.go index ce3daf6c8b..a7a2b8dd91 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator_test.go @@ -27,7 +27,7 @@ import ( rbacv1 "k8s.io/api/rbac/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextensionsfake "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/fake" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" meta "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -46,7 +46,7 @@ import ( apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" apiregistrationfake "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/fake" - v1 "github.com/operator-framework/api/pkg/operators/v1" + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned/fake" @@ -254,7 +254,7 @@ func NewFakeOperator(ctx context.Context, options ...fakeOperatorOption) (*Opera for _, ns := range config.namespaces { _, err := config.operatorClient.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}, metav1.CreateOptions{}) // Ignore already-exists errors - if err != nil && !k8serrors.IsAlreadyExists(err) { + if err != nil && !apierrors.IsAlreadyExists(err) { return nil, err } } @@ -844,25 +844,25 @@ func TestTransitionCSV(t *testing.T) { apiHash, err := resolvercache.APIKeyToGVKHash(opregistry.APIKey{Group: "g1", Version: "v1", Kind: "c1"}) require.NoError(t, err) - defaultOperatorGroup := &v1.OperatorGroup{ + defaultOperatorGroup := &operatorsv1.OperatorGroup{ TypeMeta: metav1.TypeMeta{ Kind: "OperatorGroup", - APIVersion: v1.SchemeGroupVersion.String(), + APIVersion: operatorsv1.SchemeGroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: "default", Namespace: namespace, }, - Spec: v1.OperatorGroupSpec{}, - Status: v1.OperatorGroupStatus{ + Spec: operatorsv1.OperatorGroupSpec{}, + Status: operatorsv1.OperatorGroupStatus{ Namespaces: []string{namespace}, }, } defaultTemplateAnnotations := map[string]string{ - v1.OperatorGroupTargetsAnnotationKey: namespace, - v1.OperatorGroupNamespaceAnnotationKey: namespace, - v1.OperatorGroupAnnotationKey: defaultOperatorGroup.GetName(), + operatorsv1.OperatorGroupTargetsAnnotationKey: namespace, + operatorsv1.OperatorGroupNamespaceAnnotationKey: namespace, + operatorsv1.OperatorGroupAnnotationKey: defaultOperatorGroup.GetName(), } // Generate valid and expired CA fixtures @@ -919,7 +919,7 @@ func TestTransitionCSV(t *testing.T) { v1alpha1.CSVPhaseNone, ), defaultTemplateAnnotations), }, - clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, v1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, + clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, }, expected: expected{ csvStates: map[string]csvState{ @@ -941,7 +941,7 @@ func TestTransitionCSV(t *testing.T) { v1alpha1.CSVPhaseNone, ), defaultTemplateAnnotations), nil, apis("a1.corev1.a1Kind")), }, - clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, v1.OperatorGroupProvidedAPIsAnnotationKey, "a1Kind.corev1.a1")}, + clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, "a1Kind.corev1.a1")}, }, expected: expected{ csvStates: map[string]csvState{ @@ -976,7 +976,7 @@ func TestTransitionCSV(t *testing.T) { v1alpha1.CSVPhasePending, ), defaultTemplateAnnotations), types.UID("csv-uid")), }, - clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, v1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, + clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, crds: []runtime.Object{ crd("c1", "v1", "g1"), }, @@ -1015,7 +1015,7 @@ func TestTransitionCSV(t *testing.T) { v1alpha1.CSVPhasePending, ), defaultTemplateAnnotations), }, - clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, v1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, + clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, crds: []runtime.Object{}, }, expected: expected{ @@ -1118,7 +1118,7 @@ func TestTransitionCSV(t *testing.T) { v1alpha1.CSVPhasePending, ), defaultTemplateAnnotations), apis("a1.v1.a1Kind"), nil), }, - clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, v1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1,a1Kind.v1.a1")}, + clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1,a1Kind.v1.a1")}, crds: []runtime.Object{ crd("c1", "v1", "g1"), }, @@ -1155,7 +1155,7 @@ func TestTransitionCSV(t *testing.T) { v1alpha1.CSVPhasePending, ), defaultTemplateAnnotations), }, - clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, v1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, + clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, crds: []runtime.Object{ crd("c1", "v1", "g1"), }, @@ -1201,7 +1201,7 @@ func TestTransitionCSV(t *testing.T) { ), defaultTemplateAnnotations), apis("a1.v1.a1Kind"), nil), }, - clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, v1.OperatorGroupProvidedAPIsAnnotationKey, "a1Kind.v1.a1")}, + clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, "a1Kind.v1.a1")}, apis: []runtime.Object{apiService("a1", "v1", "a1-service", namespace, "", validCAPEM, apiregistrationv1.ConditionTrue, ownerLabelFromCSV("csv1", namespace))}, objs: []runtime.Object{ withLabels( @@ -1274,7 +1274,7 @@ func TestTransitionCSV(t *testing.T) { v1alpha1.CSVPhaseFailed, ), defaultTemplateAnnotations), }, - clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, v1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, + clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, crds: []runtime.Object{ crd("c1", "v1", "g1"), }, @@ -1299,7 +1299,7 @@ func TestTransitionCSV(t *testing.T) { v1alpha1.CSVPhaseFailed, ), defaultTemplateAnnotations), }, - clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, v1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, + clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, objs: []runtime.Object{ deployment("a1", namespace, "sa", defaultTemplateAnnotations), }, @@ -1324,7 +1324,7 @@ func TestTransitionCSV(t *testing.T) { v1alpha1.CSVPhasePending, ), defaultTemplateAnnotations), }, - clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, v1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, + clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, crds: []runtime.Object{ crd("c1", "v1", "g1"), }, @@ -1372,7 +1372,7 @@ func TestTransitionCSV(t *testing.T) { v1alpha1.CSVPhaseInstallReady, ), defaultTemplateAnnotations), }, - clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, v1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, + clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1")}, crds: []runtime.Object{ crd("c1", "v1", "g1"), }, @@ -1397,7 +1397,7 @@ func TestTransitionCSV(t *testing.T) { v1alpha1.CSVPhaseInstallReady, ), defaultTemplateAnnotations), apis("a1.v1.a1Kind"), nil), }, - clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, v1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1,a1Kind.v1.a1")}, + clientObjs: []runtime.Object{addAnnotation(defaultOperatorGroup, operatorsv1.OperatorGroupProvidedAPIsAnnotationKey, "c1.v1.g1,a1Kind.v1.a1")}, crds: []runtime.Object{ crd("c1", "v1", "g1"), }, @@ -2135,17 +2135,17 @@ func TestTransitionCSV(t *testing.T) { }, clientObjs: []runtime.Object{ defaultOperatorGroup, - &v1.OperatorGroup{ + &operatorsv1.OperatorGroup{ TypeMeta: metav1.TypeMeta{ Kind: "OperatorGroup", - APIVersion: v1.SchemeGroupVersion.String(), + APIVersion: operatorsv1.SchemeGroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: "default-2", Namespace: namespace, }, - Spec: v1.OperatorGroupSpec{}, - Status: v1.OperatorGroupStatus{ + Spec: operatorsv1.OperatorGroupSpec{}, + Status: operatorsv1.OperatorGroupStatus{ Namespaces: []string{namespace}, }, }, @@ -2183,17 +2183,17 @@ func TestTransitionCSV(t *testing.T) { ), defaultTemplateAnnotations), v1alpha1.CSVReasonInstallSuccessful), }, clientObjs: []runtime.Object{ - &v1.OperatorGroup{ + &operatorsv1.OperatorGroup{ TypeMeta: metav1.TypeMeta{ Kind: "OperatorGroup", - APIVersion: v1.SchemeGroupVersion.String(), + APIVersion: operatorsv1.SchemeGroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: "default", Namespace: namespace, }, - Spec: v1.OperatorGroupSpec{}, - Status: v1.OperatorGroupStatus{ + Spec: operatorsv1.OperatorGroupSpec{}, + Status: operatorsv1.OperatorGroupStatus{ Namespaces: []string{namespace, "new-namespace"}, }, }, @@ -2828,7 +2828,7 @@ func TestTransitionCSV(t *testing.T) { ), defaultTemplateAnnotations), }, clientObjs: []runtime.Object{ - func() *v1.OperatorGroup { + func() *operatorsv1.OperatorGroup { // Make the default OperatorGroup static static := defaultOperatorGroup.DeepCopy() static.Spec.StaticProvidedAPIs = true @@ -2858,7 +2858,7 @@ func TestTransitionCSV(t *testing.T) { ), defaultTemplateAnnotations), }, clientObjs: []runtime.Object{ - func() *v1.OperatorGroup { + func() *operatorsv1.OperatorGroup { // Make the default OperatorGroup static static := defaultOperatorGroup.DeepCopy() static.Spec.StaticProvidedAPIs = true @@ -2888,7 +2888,7 @@ func TestTransitionCSV(t *testing.T) { ), defaultTemplateAnnotations), }, clientObjs: []runtime.Object{ - func() *v1.OperatorGroup { + func() *operatorsv1.OperatorGroup { // Make the default OperatorGroup static static := defaultOperatorGroup.DeepCopy() static.Spec.StaticProvidedAPIs = true @@ -2941,7 +2941,7 @@ func TestTransitionCSV(t *testing.T) { ), v1alpha1.CSVReasonCannotModifyStaticOperatorGroupProvidedAPIs), defaultTemplateAnnotations), }, clientObjs: []runtime.Object{ - func() *v1.OperatorGroup { + func() *operatorsv1.OperatorGroup { // Make the default OperatorGroup static static := defaultOperatorGroup.DeepCopy() static.Spec.StaticProvidedAPIs = true @@ -2994,7 +2994,7 @@ func TestTransitionCSV(t *testing.T) { ), v1alpha1.CSVReasonCannotModifyStaticOperatorGroupProvidedAPIs), defaultTemplateAnnotations), }, clientObjs: []runtime.Object{ - func() *v1.OperatorGroup { + func() *operatorsv1.OperatorGroup { // Make the default OperatorGroup static static := defaultOperatorGroup.DeepCopy() static.Spec.StaticProvidedAPIs = true @@ -3024,7 +3024,7 @@ func TestTransitionCSV(t *testing.T) { ), v1alpha1.CSVReasonCannotModifyStaticOperatorGroupProvidedAPIs), defaultTemplateAnnotations), }, clientObjs: []runtime.Object{ - func() *v1.OperatorGroup { + func() *operatorsv1.OperatorGroup { // Make the default OperatorGroup static static := defaultOperatorGroup.DeepCopy() static.Spec.StaticProvidedAPIs = true @@ -3332,26 +3332,26 @@ func TestUpdates(t *testing.T) { // A - replacedby -> B - replacedby -> C namespace := "ns" - defaultOperatorGroup := &v1.OperatorGroup{ + defaultOperatorGroup := &operatorsv1.OperatorGroup{ TypeMeta: metav1.TypeMeta{ Kind: "OperatorGroup", - APIVersion: v1.SchemeGroupVersion.String(), + APIVersion: operatorsv1.SchemeGroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: "default", Namespace: namespace, }, - Spec: v1.OperatorGroupSpec{ + Spec: operatorsv1.OperatorGroupSpec{ TargetNamespaces: []string{namespace}, }, - Status: v1.OperatorGroupStatus{ + Status: operatorsv1.OperatorGroupStatus{ Namespaces: []string{namespace}, }, } defaultTemplateAnnotations := map[string]string{ - v1.OperatorGroupTargetsAnnotationKey: namespace, - v1.OperatorGroupNamespaceAnnotationKey: namespace, - v1.OperatorGroupAnnotationKey: defaultOperatorGroup.GetName(), + operatorsv1.OperatorGroupTargetsAnnotationKey: namespace, + operatorsv1.OperatorGroupNamespaceAnnotationKey: namespace, + operatorsv1.OperatorGroupAnnotationKey: defaultOperatorGroup.GetName(), } runningOperator := []runtime.Object{ withLabels( @@ -3780,7 +3780,7 @@ func TestSyncOperatorGroups(t *testing.T) { }) annotatedDeployment := ownedDeployment.DeepCopy() - annotatedDeployment.Spec.Template.SetAnnotations(map[string]string{v1.OperatorGroupTargetsAnnotationKey: operatorNamespace + "," + targetNamespace, v1.OperatorGroupAnnotationKey: "operator-group-1", v1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}) + annotatedDeployment.Spec.Template.SetAnnotations(map[string]string{operatorsv1.OperatorGroupTargetsAnnotationKey: operatorNamespace + "," + targetNamespace, operatorsv1.OperatorGroupAnnotationKey: "operator-group-1", operatorsv1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}) annotatedDeployment.SetLabels(map[string]string{ "olm.owner": "csv1", "olm.owner.namespace": "operator-ns", @@ -3789,7 +3789,7 @@ func TestSyncOperatorGroups(t *testing.T) { }) annotatedGlobalDeployment := ownedDeployment.DeepCopy() - annotatedGlobalDeployment.Spec.Template.SetAnnotations(map[string]string{v1.OperatorGroupTargetsAnnotationKey: "", v1.OperatorGroupAnnotationKey: "operator-group-1", v1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}) + annotatedGlobalDeployment.Spec.Template.SetAnnotations(map[string]string{operatorsv1.OperatorGroupTargetsAnnotationKey: "", operatorsv1.OperatorGroupAnnotationKey: "operator-group-1", operatorsv1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}) annotatedGlobalDeployment.SetLabels(map[string]string{ "olm.owner": "csv1", "olm.owner.namespace": "operator-ns", @@ -3838,7 +3838,7 @@ func TestSyncOperatorGroups(t *testing.T) { } type initial struct { - operatorGroup *v1.OperatorGroup + operatorGroup *operatorsv1.OperatorGroup clientObjs []runtime.Object crds []runtime.Object k8sObjs []runtime.Object @@ -3851,7 +3851,7 @@ func TestSyncOperatorGroups(t *testing.T) { initial initial name string expectedEqual bool - expectedStatus v1.OperatorGroupStatus + expectedStatus operatorsv1.OperatorGroupStatus final final ignoreCopyError bool }{ @@ -3859,12 +3859,12 @@ func TestSyncOperatorGroups(t *testing.T) { name: "NoMatchingNamespace/NoCSVs", expectedEqual: true, initial: initial{ - operatorGroup: &v1.OperatorGroup{ + operatorGroup: &operatorsv1.OperatorGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "operator-group-1", Namespace: operatorNamespace, }, - Spec: v1.OperatorGroupSpec{ + Spec: operatorsv1.OperatorGroupSpec{ Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{"a": "app-a"}, }, @@ -3883,18 +3883,18 @@ func TestSyncOperatorGroups(t *testing.T) { }, }, }, - expectedStatus: v1.OperatorGroupStatus{}, + expectedStatus: operatorsv1.OperatorGroupStatus{}, }, { name: "NoMatchingNamespace/CSVPresent", expectedEqual: true, initial: initial{ - operatorGroup: &v1.OperatorGroup{ + operatorGroup: &operatorsv1.OperatorGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "operator-group-1", Namespace: operatorNamespace, }, - Spec: v1.OperatorGroupSpec{ + Spec: operatorsv1.OperatorGroupSpec{ Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{"a": "app-a"}, }, @@ -3919,10 +3919,10 @@ func TestSyncOperatorGroups(t *testing.T) { }, crds: []runtime.Object{crd}, }, - expectedStatus: v1.OperatorGroupStatus{}, + expectedStatus: operatorsv1.OperatorGroupStatus{}, final: final{objects: map[string][]runtime.Object{ operatorNamespace: { - withAnnotations(operatorCSVFailedNoTargetNS.DeepCopy(), map[string]string{v1.OperatorGroupAnnotationKey: "operator-group-1", v1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}), + withAnnotations(operatorCSVFailedNoTargetNS.DeepCopy(), map[string]string{operatorsv1.OperatorGroupAnnotationKey: "operator-group-1", operatorsv1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}), }, }}, ignoreCopyError: true, @@ -3931,12 +3931,12 @@ func TestSyncOperatorGroups(t *testing.T) { name: "MatchingNamespace/NoCSVs", expectedEqual: true, initial: initial{ - operatorGroup: &v1.OperatorGroup{ + operatorGroup: &operatorsv1.OperatorGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "operator-group-1", Namespace: operatorNamespace, }, - Spec: v1.OperatorGroupSpec{ + Spec: operatorsv1.OperatorGroupSpec{ Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{"app": "app-a"}, }, @@ -3956,7 +3956,7 @@ func TestSyncOperatorGroups(t *testing.T) { }, }, }, - expectedStatus: v1.OperatorGroupStatus{ + expectedStatus: operatorsv1.OperatorGroupStatus{ Namespaces: []string{targetNamespace}, LastUpdated: &now, }, @@ -3965,12 +3965,12 @@ func TestSyncOperatorGroups(t *testing.T) { name: "MatchingNamespace/CSVPresent/Found", expectedEqual: true, initial: initial{ - operatorGroup: &v1.OperatorGroup{ + operatorGroup: &operatorsv1.OperatorGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "operator-group-1", Namespace: operatorNamespace, }, - Spec: v1.OperatorGroupSpec{ + Spec: operatorsv1.OperatorGroupSpec{ Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{"app": "app-a"}, }, @@ -3997,18 +3997,18 @@ func TestSyncOperatorGroups(t *testing.T) { }, crds: []runtime.Object{crd}, }, - expectedStatus: v1.OperatorGroupStatus{ + expectedStatus: operatorsv1.OperatorGroupStatus{ Namespaces: []string{operatorNamespace, targetNamespace}, LastUpdated: &now, }, final: final{objects: map[string][]runtime.Object{ operatorNamespace: { - withAnnotations(operatorCSVFinal.DeepCopy(), map[string]string{v1.OperatorGroupTargetsAnnotationKey: operatorNamespace + "," + targetNamespace, v1.OperatorGroupAnnotationKey: "operator-group-1", v1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}), + withAnnotations(operatorCSVFinal.DeepCopy(), map[string]string{operatorsv1.OperatorGroupTargetsAnnotationKey: operatorNamespace + "," + targetNamespace, operatorsv1.OperatorGroupAnnotationKey: "operator-group-1", operatorsv1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}), annotatedDeployment, }, targetNamespace: { withLabels( - withAnnotations(targetCSV.DeepCopy(), map[string]string{v1.OperatorGroupAnnotationKey: "operator-group-1", v1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}), + withAnnotations(targetCSV.DeepCopy(), map[string]string{operatorsv1.OperatorGroupAnnotationKey: "operator-group-1", operatorsv1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}), labels.Merge(targetCSV.GetLabels(), map[string]string{v1alpha1.CopiedLabelKey: operatorNamespace}), ), &rbacv1.Role{ @@ -4071,12 +4071,12 @@ func TestSyncOperatorGroups(t *testing.T) { name: "MatchingNamespace/CSVPresent/Found/ExplicitTargetNamespaces", expectedEqual: true, initial: initial{ - operatorGroup: &v1.OperatorGroup{ + operatorGroup: &operatorsv1.OperatorGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "operator-group-1", Namespace: operatorNamespace, }, - Spec: v1.OperatorGroupSpec{ + Spec: operatorsv1.OperatorGroupSpec{ TargetNamespaces: []string{operatorNamespace, targetNamespace}, }, }, @@ -4099,18 +4099,18 @@ func TestSyncOperatorGroups(t *testing.T) { }, crds: []runtime.Object{crd}, }, - expectedStatus: v1.OperatorGroupStatus{ + expectedStatus: operatorsv1.OperatorGroupStatus{ Namespaces: []string{operatorNamespace, targetNamespace}, LastUpdated: &now, }, final: final{objects: map[string][]runtime.Object{ operatorNamespace: { - withAnnotations(operatorCSVFinal.DeepCopy(), map[string]string{v1.OperatorGroupTargetsAnnotationKey: operatorNamespace + "," + targetNamespace, v1.OperatorGroupAnnotationKey: "operator-group-1", v1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}), + withAnnotations(operatorCSVFinal.DeepCopy(), map[string]string{operatorsv1.OperatorGroupTargetsAnnotationKey: operatorNamespace + "," + targetNamespace, operatorsv1.OperatorGroupAnnotationKey: "operator-group-1", operatorsv1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}), annotatedDeployment, }, targetNamespace: { withLabels( - withAnnotations(targetCSV.DeepCopy(), map[string]string{v1.OperatorGroupAnnotationKey: "operator-group-1", v1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}), + withAnnotations(targetCSV.DeepCopy(), map[string]string{operatorsv1.OperatorGroupAnnotationKey: "operator-group-1", operatorsv1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}), labels.Merge(targetCSV.GetLabels(), map[string]string{v1alpha1.CopiedLabelKey: operatorNamespace}), ), &rbacv1.Role{ @@ -4173,13 +4173,13 @@ func TestSyncOperatorGroups(t *testing.T) { name: "AllNamespaces/CSVPresent/Found", expectedEqual: true, initial: initial{ - operatorGroup: &v1.OperatorGroup{ + operatorGroup: &operatorsv1.OperatorGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "operator-group-1", Namespace: operatorNamespace, Labels: map[string]string{"app": "app-a"}, }, - Spec: v1.OperatorGroupSpec{}, + Spec: operatorsv1.OperatorGroupSpec{}, }, clientObjs: []runtime.Object{operatorCSV}, k8sObjs: []runtime.Object{ @@ -4204,13 +4204,13 @@ func TestSyncOperatorGroups(t *testing.T) { }, crds: []runtime.Object{crd}, }, - expectedStatus: v1.OperatorGroupStatus{ + expectedStatus: operatorsv1.OperatorGroupStatus{ Namespaces: []string{corev1.NamespaceAll}, LastUpdated: &now, }, final: final{objects: map[string][]runtime.Object{ operatorNamespace: { - withAnnotations(operatorCSVFinal.DeepCopy(), map[string]string{v1.OperatorGroupTargetsAnnotationKey: "", v1.OperatorGroupAnnotationKey: "operator-group-1", v1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}), + withAnnotations(operatorCSVFinal.DeepCopy(), map[string]string{operatorsv1.OperatorGroupTargetsAnnotationKey: "", operatorsv1.OperatorGroupAnnotationKey: "operator-group-1", operatorsv1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}), annotatedGlobalDeployment, }, "": { @@ -4262,7 +4262,7 @@ func TestSyncOperatorGroups(t *testing.T) { }, targetNamespace: { withLabels( - withAnnotations(targetCSV.DeepCopy(), map[string]string{v1.OperatorGroupAnnotationKey: "operator-group-1", v1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}), + withAnnotations(targetCSV.DeepCopy(), map[string]string{operatorsv1.OperatorGroupAnnotationKey: "operator-group-1", operatorsv1.OperatorGroupNamespaceAnnotationKey: operatorNamespace}), labels.Merge(targetCSV.GetLabels(), map[string]string{v1alpha1.CopiedLabelKey: operatorNamespace}), ), }, @@ -4272,20 +4272,20 @@ func TestSyncOperatorGroups(t *testing.T) { name: "AllNamespaces/CSVPresent/Found/PruneMissingProvidedAPI/StaticProvidedAPIs", expectedEqual: true, initial: initial{ - operatorGroup: &v1.OperatorGroup{ + operatorGroup: &operatorsv1.OperatorGroup{ TypeMeta: metav1.TypeMeta{ - Kind: v1.OperatorGroupKind, - APIVersion: v1.GroupVersion.String(), + Kind: operatorsv1.OperatorGroupKind, + APIVersion: operatorsv1.GroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: "operator-group-1", Namespace: operatorNamespace, Labels: map[string]string{"app": "app-a"}, Annotations: map[string]string{ - v1.OperatorGroupProvidedAPIsAnnotationKey: "missing.fake.api.group", + operatorsv1.OperatorGroupProvidedAPIsAnnotationKey: "missing.fake.api.group", }, }, - Spec: v1.OperatorGroupSpec{ + Spec: operatorsv1.OperatorGroupSpec{ StaticProvidedAPIs: true, }, }, @@ -4299,29 +4299,29 @@ func TestSyncOperatorGroups(t *testing.T) { }, }, }, - expectedStatus: v1.OperatorGroupStatus{ + expectedStatus: operatorsv1.OperatorGroupStatus{ Namespaces: []string{corev1.NamespaceAll}, LastUpdated: &now, }, final: final{objects: map[string][]runtime.Object{ operatorNamespace: { - &v1.OperatorGroup{ + &operatorsv1.OperatorGroup{ TypeMeta: metav1.TypeMeta{ - Kind: v1.OperatorGroupKind, - APIVersion: v1.GroupVersion.String(), + Kind: operatorsv1.OperatorGroupKind, + APIVersion: operatorsv1.GroupVersion.String(), }, ObjectMeta: metav1.ObjectMeta{ Name: "operator-group-1", Namespace: operatorNamespace, Labels: map[string]string{"app": "app-a"}, Annotations: map[string]string{ - v1.OperatorGroupProvidedAPIsAnnotationKey: "missing.fake.api.group", + operatorsv1.OperatorGroupProvidedAPIsAnnotationKey: "missing.fake.api.group", }, }, - Spec: v1.OperatorGroupSpec{ + Spec: operatorsv1.OperatorGroupSpec{ StaticProvidedAPIs: true, }, - Status: v1.OperatorGroupStatus{ + Status: operatorsv1.OperatorGroupStatus{ Namespaces: []string{corev1.NamespaceAll}, LastUpdated: &now, }, @@ -4333,12 +4333,12 @@ func TestSyncOperatorGroups(t *testing.T) { name: "AllNamespaces/CSVPresent/InstallModeNotSupported", expectedEqual: true, initial: initial{ - operatorGroup: &v1.OperatorGroup{ + operatorGroup: &operatorsv1.OperatorGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "operator-group-1", Namespace: operatorNamespace, }, - Spec: v1.OperatorGroupSpec{}, + Spec: operatorsv1.OperatorGroupSpec{}, }, clientObjs: []runtime.Object{ withInstallModes(operatorCSV.DeepCopy(), []v1alpha1.InstallMode{ @@ -4368,7 +4368,7 @@ func TestSyncOperatorGroups(t *testing.T) { }, crds: []runtime.Object{crd}, }, - expectedStatus: v1.OperatorGroupStatus{ + expectedStatus: operatorsv1.OperatorGroupStatus{ Namespaces: []string{corev1.NamespaceAll}, LastUpdated: &now, }, @@ -4377,9 +4377,9 @@ func TestSyncOperatorGroups(t *testing.T) { withPhase( withInstallModes( withAnnotations(operatorCSV.DeepCopy(), map[string]string{ - v1.OperatorGroupTargetsAnnotationKey: "", - v1.OperatorGroupAnnotationKey: "operator-group-1", - v1.OperatorGroupNamespaceAnnotationKey: operatorNamespace, + operatorsv1.OperatorGroupTargetsAnnotationKey: "", + operatorsv1.OperatorGroupAnnotationKey: "operator-group-1", + operatorsv1.OperatorGroupNamespaceAnnotationKey: operatorNamespace, }).(*v1alpha1.ClusterServiceVersion), []v1alpha1.InstallMode{ { @@ -4559,7 +4559,7 @@ func TestOperatorGroupConditions(t *testing.T) { serviceAccount := serviceAccount("sa", operatorNamespace) type initial struct { - operatorGroup *v1.OperatorGroup + operatorGroup *operatorsv1.OperatorGroup clientObjs []runtime.Object k8sObjs []runtime.Object } @@ -4573,13 +4573,13 @@ func TestOperatorGroupConditions(t *testing.T) { { name: "ValidOperatorGroup/NoServiceAccount", initial: initial{ - operatorGroup: &v1.OperatorGroup{ + operatorGroup: &operatorsv1.OperatorGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "operator-group-1", Namespace: operatorNamespace, UID: "135e02a5-a7e2-44e7-abaa-88c63838993c", }, - Spec: v1.OperatorGroupSpec{ + Spec: operatorsv1.OperatorGroupSpec{ TargetNamespaces: []string{operatorNamespace}, }, }, @@ -4597,13 +4597,13 @@ func TestOperatorGroupConditions(t *testing.T) { { name: "ValidOperatorGroup/ValidServiceAccount", initial: initial{ - operatorGroup: &v1.OperatorGroup{ + operatorGroup: &operatorsv1.OperatorGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "operator-group-1", Namespace: operatorNamespace, UID: "135e02a5-a7e2-44e7-abaa-88c63838993c", }, - Spec: v1.OperatorGroupSpec{ + Spec: operatorsv1.OperatorGroupSpec{ ServiceAccountName: "sa", TargetNamespaces: []string{operatorNamespace}, }, @@ -4623,13 +4623,13 @@ func TestOperatorGroupConditions(t *testing.T) { { name: "BadOperatorGroup/MissingServiceAccount", initial: initial{ - operatorGroup: &v1.OperatorGroup{ + operatorGroup: &operatorsv1.OperatorGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "operator-group-1", Namespace: operatorNamespace, UID: "135e02a5-a7e2-44e7-abaa-88c63838993c", }, - Spec: v1.OperatorGroupSpec{ + Spec: operatorsv1.OperatorGroupSpec{ ServiceAccountName: "nonexistingSA", TargetNamespaces: []string{operatorNamespace}, }, @@ -4645,9 +4645,9 @@ func TestOperatorGroupConditions(t *testing.T) { expectError: true, expectedConditions: []metav1.Condition{ { - Type: v1.OperatorGroupServiceAccountCondition, + Type: operatorsv1.OperatorGroupServiceAccountCondition, Status: metav1.ConditionTrue, - Reason: v1.OperatorGroupServiceAccountReason, + Reason: operatorsv1.OperatorGroupServiceAccountReason, Message: "ServiceAccount nonexistingSA not found", }, }, @@ -4655,24 +4655,24 @@ func TestOperatorGroupConditions(t *testing.T) { { name: "BadOperatorGroup/MultipleOperatorGroups", initial: initial{ - operatorGroup: &v1.OperatorGroup{ + operatorGroup: &operatorsv1.OperatorGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "operator-group-1", Namespace: operatorNamespace, UID: "135e02a5-a7e2-44e7-abaa-88c63838993c", }, - Spec: v1.OperatorGroupSpec{ + Spec: operatorsv1.OperatorGroupSpec{ TargetNamespaces: []string{operatorNamespace}, }, }, clientObjs: []runtime.Object{ - &v1.OperatorGroup{ + &operatorsv1.OperatorGroup{ ObjectMeta: metav1.ObjectMeta{ Name: "operator-group-2", Namespace: operatorNamespace, UID: "cdc9643e-7c52-4f7c-ae75-28ccb6aec97d", }, - Spec: v1.OperatorGroupSpec{ + Spec: operatorsv1.OperatorGroupSpec{ TargetNamespaces: []string{operatorNamespace, "some-namespace"}, }, }, @@ -4688,9 +4688,9 @@ func TestOperatorGroupConditions(t *testing.T) { expectError: true, expectedConditions: []metav1.Condition{ { - Type: v1.MutlipleOperatorGroupCondition, + Type: operatorsv1.MutlipleOperatorGroupCondition, Status: metav1.ConditionTrue, - Reason: v1.MultipleOperatorGroupsReason, + Reason: operatorsv1.MultipleOperatorGroupsReason, Message: "Multiple OperatorGroup found in the same namespace", }, }, @@ -4760,7 +4760,7 @@ func RequireObjectsInCache(t *testing.T, lister operatorlister.OperatorLister, n fetched, err = lister.RbacV1().RoleBindingLister().RoleBindings(namespace).Get(o.GetName()) case *v1alpha1.ClusterServiceVersion: fetched, err = lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(namespace).Get(o.GetName()) - case *v1.OperatorGroup: + case *operatorsv1.OperatorGroup: fetched, err = lister.OperatorsV1().OperatorGroupLister().OperatorGroups(namespace).Get(o.GetName()) default: require.Failf(t, "couldn't find expected object", "%#v", object) @@ -4799,7 +4799,7 @@ func RequireObjectsInNamespace(t *testing.T, opClient operatorclient.ClientInter // and this will still check that the final state is correct object.(*v1alpha1.ClusterServiceVersion).Status.Conditions = nil fetched.(*v1alpha1.ClusterServiceVersion).Status.Conditions = nil - case *v1.OperatorGroup: + case *operatorsv1.OperatorGroup: fetched, err = client.OperatorsV1().OperatorGroups(namespace).Get(context.TODO(), o.GetName(), metav1.GetOptions{}) default: require.Failf(t, "couldn't find expected object", "%#v", object) diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorconditions.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorconditions.go index 04ba9a7ebe..1abf628398 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorconditions.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorconditions.go @@ -3,7 +3,7 @@ package olm import ( "fmt" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" meta "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -19,7 +19,7 @@ func (a *Operator) isOperatorUpgradeable(csv *v1alpha1.ClusterServiceVersion) (b cond, err := a.lister.OperatorsV2().OperatorConditionLister().OperatorConditions(csv.GetNamespace()).Get(csv.GetName()) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return true, nil } return false, err diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go index e7ca97a4ce..cd135c8058 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/olm/operatorgroup.go @@ -7,17 +7,17 @@ import ( "reflect" "strings" - v1 "github.com/operator-framework/api/pkg/operators/v1" utillabels "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/labels" "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" meta "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/errors" + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/operator-framework/api/pkg/operators/v1alpha1" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/decorators" @@ -54,7 +54,7 @@ func aggregationLabelFromAPIKey(k opregistry.APIKey, suffix string) (string, err } func (a *Operator) syncOperatorGroups(obj interface{}) error { - op, ok := obj.(*v1.OperatorGroup) + op, ok := obj.(*operatorsv1.OperatorGroup) if !ok { a.logger.Debugf("wrong type: %#v\n", obj) return fmt.Errorf("casting OperatorGroup failed") @@ -74,10 +74,10 @@ func (a *Operator) syncOperatorGroups(obj interface{}) error { // Check if there is a stale multiple OG condition and clear it if existed. if len(groups) == 1 { og := groups[0].DeepCopy() - if c := meta.FindStatusCondition(og.Status.Conditions, v1.MutlipleOperatorGroupCondition); c != nil { - meta.RemoveStatusCondition(&og.Status.Conditions, v1.MutlipleOperatorGroupCondition) + if c := meta.FindStatusCondition(og.Status.Conditions, operatorsv1.MutlipleOperatorGroupCondition); c != nil { + meta.RemoveStatusCondition(&og.Status.Conditions, operatorsv1.MutlipleOperatorGroupCondition) if og.GetName() == op.GetName() { - meta.RemoveStatusCondition(&op.Status.Conditions, v1.MutlipleOperatorGroupCondition) + meta.RemoveStatusCondition(&op.Status.Conditions, operatorsv1.MutlipleOperatorGroupCondition) } _, err = a.client.OperatorsV1().OperatorGroups(op.GetNamespace()).UpdateStatus(context.TODO(), og, metav1.UpdateOptions{}) if err != nil { @@ -88,14 +88,14 @@ func (a *Operator) syncOperatorGroups(obj interface{}) error { // Add to all OG's status conditions to indicate they're multiple OGs in the // same namespace which is not allowed. cond := metav1.Condition{ - Type: v1.MutlipleOperatorGroupCondition, + Type: operatorsv1.MutlipleOperatorGroupCondition, Status: metav1.ConditionTrue, - Reason: v1.MultipleOperatorGroupsReason, + Reason: operatorsv1.MultipleOperatorGroupsReason, Message: "Multiple OperatorGroup found in the same namespace", } for i := range groups { og := groups[i].DeepCopy() - if c := meta.FindStatusCondition(og.Status.Conditions, v1.MutlipleOperatorGroupCondition); c != nil { + if c := meta.FindStatusCondition(og.Status.Conditions, operatorsv1.MutlipleOperatorGroupCondition); c != nil { continue } meta.SetStatusCondition(&og.Status.Conditions, cond) @@ -122,7 +122,7 @@ func (a *Operator) syncOperatorGroups(obj interface{}) error { } for i := range csvList { csv := csvList[i].DeepCopy() - if group, ok := csv.GetAnnotations()[v1.OperatorGroupAnnotationKey]; !ok || group != op.GetName() { + if group, ok := csv.GetAnnotations()[operatorsv1.OperatorGroupAnnotationKey]; !ok || group != op.GetName() { continue } if csv.Status.Reason == v1alpha1.CSVReasonComponentFailedNoRetry { @@ -152,13 +152,13 @@ func (a *Operator) syncOperatorGroups(obj interface{}) error { // Update operatorgroup target namespace selection logger.WithField("targets", targetNamespaces).Debug("namespace change detected") - op.Status = v1.OperatorGroupStatus{ + op.Status = operatorsv1.OperatorGroupStatus{ Namespaces: targetNamespaces, LastUpdated: a.now(), Conditions: op.Status.Conditions, } - if _, err = a.client.OperatorsV1().OperatorGroups(op.GetNamespace()).UpdateStatus(context.TODO(), op, metav1.UpdateOptions{}); err != nil && !k8serrors.IsNotFound(err) { + if _, err = a.client.OperatorsV1().OperatorGroups(op.GetNamespace()).UpdateStatus(context.TODO(), op, metav1.UpdateOptions{}); err != nil && !apierrors.IsNotFound(err) { logger.WithError(err).Warn("operatorgroup update failed") return err } @@ -223,7 +223,7 @@ func (a *Operator) syncOperatorGroups(obj interface{}) error { } func (a *Operator) operatorGroupDeleted(obj interface{}) { - op, ok := obj.(*v1.OperatorGroup) + op, ok := obj.(*operatorsv1.OperatorGroup) if !ok { a.logger.Debugf("casting OperatorGroup failed, wrong type: %#v\n", obj) return @@ -254,7 +254,7 @@ func (a *Operator) operatorGroupDeleted(obj interface{}) { } } -func (a *Operator) annotateCSVs(group *v1.OperatorGroup, targetNamespaces []string, logger *logrus.Entry) error { +func (a *Operator) annotateCSVs(group *operatorsv1.OperatorGroup, targetNamespaces []string, logger *logrus.Entry) error { updateErrs := []error{} targetNamespaceSet := NewNamespaceSet(targetNamespaces) @@ -264,13 +264,13 @@ func (a *Operator) annotateCSVs(group *v1.OperatorGroup, targetNamespaces []stri } logger := logger.WithField("csv", csv.GetName()) - originalNamespacesAnnotation := a.copyOperatorGroupAnnotations(&csv.ObjectMeta)[v1.OperatorGroupTargetsAnnotationKey] + originalNamespacesAnnotation := a.copyOperatorGroupAnnotations(&csv.ObjectMeta)[operatorsv1.OperatorGroupTargetsAnnotationKey] originalNamespaceSet := NewNamespaceSetFromString(originalNamespacesAnnotation) if a.operatorGroupAnnotationsDiffer(&csv.ObjectMeta, group) { a.setOperatorGroupAnnotations(&csv.ObjectMeta, group, true) // CRDs don't support strategic merge patching, but in the future if they do this should be updated to patch - if _, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).Update(context.TODO(), csv, metav1.UpdateOptions{}); err != nil && !k8serrors.IsNotFound(err) { + if _, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).Update(context.TODO(), csv, metav1.UpdateOptions{}); err != nil && !apierrors.IsNotFound(err) { logger.WithError(err).Warnf("error adding operatorgroup annotations") updateErrs = append(updateErrs, err) continue @@ -298,7 +298,7 @@ func (a *Operator) annotateCSVs(group *v1.OperatorGroup, targetNamespaces []stri return errors.NewAggregate(updateErrs) } -func (a *Operator) providedAPIsFromCSVs(group *v1.OperatorGroup, logger *logrus.Entry) map[opregistry.APIKey]*v1alpha1.ClusterServiceVersion { +func (a *Operator) providedAPIsFromCSVs(group *operatorsv1.OperatorGroup, logger *logrus.Entry) map[opregistry.APIKey]*v1alpha1.ClusterServiceVersion { set := a.csvSet(group.Namespace, v1alpha1.CSVPhaseAny) providedAPIsFromCSVs := make(map[opregistry.APIKey]*v1alpha1.ClusterServiceVersion) for _, csv := range set { @@ -323,7 +323,7 @@ func (a *Operator) providedAPIsFromCSVs(group *v1.OperatorGroup, logger *logrus. return providedAPIsFromCSVs } -func (a *Operator) pruneProvidedAPIs(group *v1.OperatorGroup, groupProvidedAPIs cache.APISet, providedAPIsFromCSVs map[opregistry.APIKey]*v1alpha1.ClusterServiceVersion, logger *logrus.Entry) { +func (a *Operator) pruneProvidedAPIs(group *operatorsv1.OperatorGroup, groupProvidedAPIs cache.APISet, providedAPIsFromCSVs map[opregistry.APIKey]*v1alpha1.ClusterServiceVersion, logger *logrus.Entry) { // Don't prune providedAPIsFromCSVs if static if group.Spec.StaticProvidedAPIs { a.logger.Debug("group has static provided apis. skipping provided api pruning") @@ -337,7 +337,7 @@ func (a *Operator) pruneProvidedAPIs(group *v1.OperatorGroup, groupProvidedAPIs } else { csv := providedAPIsFromCSVs[api] _, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(csv.GetNamespace()).Get(csv.GetName()) - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { continue } if csv.DeletionTimestamp == nil && (csv.Status.Phase == v1alpha1.CSVPhaseNone || csv.Status.Phase == v1alpha1.CSVPhasePending) { @@ -360,10 +360,10 @@ func (a *Operator) pruneProvidedAPIs(group *v1.OperatorGroup, groupProvidedAPIs // Don't need to check for nil annotations since we already know |annotations| > 0 annotations := group.GetAnnotations() - annotations[v1.OperatorGroupProvidedAPIsAnnotationKey] = intersection.String() + annotations[operatorsv1.OperatorGroupProvidedAPIsAnnotationKey] = intersection.String() group.SetAnnotations(annotations) logger.Debug("removing provided apis from annotation to match cluster state") - if _, err := a.client.OperatorsV1().OperatorGroups(group.GetNamespace()).Update(context.TODO(), group, metav1.UpdateOptions{}); err != nil && !k8serrors.IsNotFound(err) { + if _, err := a.client.OperatorsV1().OperatorGroups(group.GetNamespace()).Update(context.TODO(), group, metav1.UpdateOptions{}); err != nil && !apierrors.IsNotFound(err) { logger.WithError(err).Warn("could not update provided api annotations") } } @@ -390,15 +390,15 @@ func (a *Operator) ensureProvidedAPIClusterRole(namePrefix, suffix string, verbs } existingCR, err := a.lister.RbacV1().ClusterRoleLister().Get(clusterRole.Name) - if err != nil && !k8serrors.IsNotFound(err) { + if err != nil && !apierrors.IsNotFound(err) { return err } - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { existingCR, err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), clusterRole, metav1.CreateOptions{}) if err == nil { return nil } - if !k8serrors.IsAlreadyExists(err) { + if !apierrors.IsAlreadyExists(err) { a.logger.WithError(err).Errorf("Create cluster role failed: %v", clusterRole) return err } @@ -456,7 +456,7 @@ func (a *Operator) ensureClusterRolesForCSV(csv *v1alpha1.ClusterServiceVersion) return nil } -func (a *Operator) ensureRBACInTargetNamespace(csv *v1alpha1.ClusterServiceVersion, operatorGroup *v1.OperatorGroup) error { +func (a *Operator) ensureRBACInTargetNamespace(csv *v1alpha1.ClusterServiceVersion, operatorGroup *operatorsv1.OperatorGroup) error { targetNamespaces := operatorGroup.Status.Namespaces if targetNamespaces == nil { return nil @@ -535,7 +535,7 @@ func (a *Operator) ensureSingletonRBAC(operatorNamespace string, csv *v1alpha1.C // TODO: this should do something smarter if the cluster role already exists if cr, err := a.opClient.CreateClusterRole(clusterRole); err != nil { // If the CR already exists, but the label is correct, the cache is just behind - if k8serrors.IsAlreadyExists(err) && cr != nil && ownerutil.IsOwnedByLabel(cr, csv) { + if apierrors.IsAlreadyExists(err) && cr != nil && ownerutil.IsOwnedByLabel(cr, csv) { continue } return err @@ -574,7 +574,7 @@ func (a *Operator) ensureSingletonRBAC(operatorNamespace string, csv *v1alpha1.C // TODO: this should do something smarter if the cluster role binding already exists if crb, err := a.opClient.CreateClusterRoleBinding(clusterRoleBinding); err != nil { // If the CRB already exists, but the label is correct, the cache is just behind - if k8serrors.IsAlreadyExists(err) && crb != nil && ownerutil.IsOwnedByLabel(crb, csv) { + if apierrors.IsAlreadyExists(err) && crb != nil && ownerutil.IsOwnedByLabel(crb, csv) { continue } return err @@ -688,7 +688,7 @@ func (a *Operator) ensureTenantRBAC(operatorNamespace, targetNamespace string, c return nil } -func (a *Operator) ensureCSVsInNamespaces(csv *v1alpha1.ClusterServiceVersion, operatorGroup *v1.OperatorGroup, targets NamespaceSet) error { +func (a *Operator) ensureCSVsInNamespaces(csv *v1alpha1.ClusterServiceVersion, operatorGroup *operatorsv1.OperatorGroup, targets NamespaceSet) error { namespaces, err := a.lister.CoreV1().NamespaceLister().List(labels.Everything()) if err != nil { return err @@ -798,7 +798,7 @@ func (a *Operator) copyToNamespace(prototype *v1alpha1.ClusterServiceVersion, ns prototype.UID = "" existing, err := a.copiedCSVLister.ClusterServiceVersions(nsTo).Get(prototype.GetName()) - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { created, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(nsTo).Create(context.TODO(), prototype, metav1.CreateOptions{}) if err != nil { return nil, err @@ -855,7 +855,7 @@ func (a *Operator) pruneFromNamespace(operatorGroupName, namespace string) error } for _, csv := range fetchedCSVs { - if csv.IsCopied() && csv.GetAnnotations()[v1.OperatorGroupAnnotationKey] == operatorGroupName { + if csv.IsCopied() && csv.GetAnnotations()[operatorsv1.OperatorGroupAnnotationKey] == operatorGroupName { a.logger.Debugf("Found CSV '%v' in namespace %v to delete", csv.GetName(), namespace) if err := a.copiedCSVGCQueueSet.Requeue(csv.GetNamespace(), csv.GetName()); err != nil { return err @@ -865,36 +865,36 @@ func (a *Operator) pruneFromNamespace(operatorGroupName, namespace string) error return nil } -func (a *Operator) setOperatorGroupAnnotations(obj *metav1.ObjectMeta, op *v1.OperatorGroup, addTargets bool) { - metav1.SetMetaDataAnnotation(obj, v1.OperatorGroupNamespaceAnnotationKey, op.GetNamespace()) - metav1.SetMetaDataAnnotation(obj, v1.OperatorGroupAnnotationKey, op.GetName()) +func (a *Operator) setOperatorGroupAnnotations(obj *metav1.ObjectMeta, op *operatorsv1.OperatorGroup, addTargets bool) { + metav1.SetMetaDataAnnotation(obj, operatorsv1.OperatorGroupNamespaceAnnotationKey, op.GetNamespace()) + metav1.SetMetaDataAnnotation(obj, operatorsv1.OperatorGroupAnnotationKey, op.GetName()) if addTargets && op.Status.Namespaces != nil { - metav1.SetMetaDataAnnotation(obj, v1.OperatorGroupTargetsAnnotationKey, op.BuildTargetNamespaces()) + metav1.SetMetaDataAnnotation(obj, operatorsv1.OperatorGroupTargetsAnnotationKey, op.BuildTargetNamespaces()) } } -func (a *Operator) operatorGroupAnnotationsDiffer(obj *metav1.ObjectMeta, op *v1.OperatorGroup) bool { +func (a *Operator) operatorGroupAnnotationsDiffer(obj *metav1.ObjectMeta, op *operatorsv1.OperatorGroup) bool { annotations := obj.GetAnnotations() if annotations == nil { return true } - if operatorGroupNamespace, ok := annotations[v1.OperatorGroupNamespaceAnnotationKey]; !ok || operatorGroupNamespace != op.GetNamespace() { + if operatorGroupNamespace, ok := annotations[operatorsv1.OperatorGroupNamespaceAnnotationKey]; !ok || operatorGroupNamespace != op.GetNamespace() { return true } - if operatorGroup, ok := annotations[v1.OperatorGroupAnnotationKey]; !ok || operatorGroup != op.GetName() { + if operatorGroup, ok := annotations[operatorsv1.OperatorGroupAnnotationKey]; !ok || operatorGroup != op.GetName() { return true } - if targets, ok := annotations[v1.OperatorGroupTargetsAnnotationKey]; !ok || targets != op.BuildTargetNamespaces() { + if targets, ok := annotations[operatorsv1.OperatorGroupTargetsAnnotationKey]; !ok || targets != op.BuildTargetNamespaces() { a.logger.WithFields(logrus.Fields{ - "annotationTargets": annotations[v1.OperatorGroupTargetsAnnotationKey], + "annotationTargets": annotations[operatorsv1.OperatorGroupTargetsAnnotationKey], "opgroupTargets": op.BuildTargetNamespaces(), }).Debug("annotations different") return true } a.logger.WithFields(logrus.Fields{ - "annotationTargets": annotations[v1.OperatorGroupTargetsAnnotationKey], + "annotationTargets": annotations[operatorsv1.OperatorGroupTargetsAnnotationKey], "opgroupTargets": op.BuildTargetNamespaces(), }).Debug("annotations correct") return false @@ -904,11 +904,11 @@ func (a *Operator) copyOperatorGroupAnnotations(obj *metav1.ObjectMeta) map[stri copiedAnnotations := make(map[string]string) for k, v := range obj.GetAnnotations() { switch k { - case v1.OperatorGroupNamespaceAnnotationKey: + case operatorsv1.OperatorGroupNamespaceAnnotationKey: fallthrough - case v1.OperatorGroupAnnotationKey: + case operatorsv1.OperatorGroupAnnotationKey: fallthrough - case v1.OperatorGroupTargetsAnnotationKey: + case operatorsv1.OperatorGroupTargetsAnnotationKey: copiedAnnotations[k] = v } } @@ -932,7 +932,7 @@ func namespacesChanged(clusterNamespaces []string, statusNamespaces []string) bo return false } -func (a *Operator) getOperatorGroupTargets(op *v1.OperatorGroup) (map[string]struct{}, error) { +func (a *Operator) getOperatorGroupTargets(op *operatorsv1.OperatorGroup) (map[string]struct{}, error) { selector, err := metav1.LabelSelectorAsSelector(op.Spec.Selector) if err != nil { @@ -964,7 +964,7 @@ func (a *Operator) getOperatorGroupTargets(op *v1.OperatorGroup) (map[string]str return namespaceSet, nil } -func (a *Operator) updateNamespaceList(op *v1.OperatorGroup) ([]string, error) { +func (a *Operator) updateNamespaceList(op *operatorsv1.OperatorGroup) ([]string, error) { namespaceSet, err := a.getOperatorGroupTargets(op) if err != nil { return nil, err @@ -977,7 +977,7 @@ func (a *Operator) updateNamespaceList(op *v1.OperatorGroup) ([]string, error) { return namespaceList, nil } -func (a *Operator) ensureOpGroupClusterRole(op *v1.OperatorGroup, suffix string, apis cache.APISet) error { +func (a *Operator) ensureOpGroupClusterRole(op *operatorsv1.OperatorGroup, suffix string, apis cache.APISet) error { clusterRole := &rbacv1.ClusterRole{ ObjectMeta: metav1.ObjectMeta{ Name: strings.Join([]string{op.GetName(), suffix}, "-"), @@ -1006,15 +1006,15 @@ func (a *Operator) ensureOpGroupClusterRole(op *v1.OperatorGroup, suffix string, } existingRole, err := a.lister.RbacV1().ClusterRoleLister().Get(clusterRole.Name) - if err != nil && !k8serrors.IsNotFound(err) { + if err != nil && !apierrors.IsNotFound(err) { return err } - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { existingRole, err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), clusterRole, metav1.CreateOptions{}) if err == nil { return nil } - if !k8serrors.IsAlreadyExists(err) { + if !apierrors.IsAlreadyExists(err) { a.logger.WithError(err).Errorf("Create cluster role failed: %v", clusterRole) return err } @@ -1031,7 +1031,7 @@ func (a *Operator) ensureOpGroupClusterRole(op *v1.OperatorGroup, suffix string, return nil } -func (a *Operator) ensureOpGroupClusterRoles(op *v1.OperatorGroup, apis cache.APISet) error { +func (a *Operator) ensureOpGroupClusterRoles(op *operatorsv1.OperatorGroup, apis cache.APISet) error { for _, suffix := range Suffices { if err := a.ensureOpGroupClusterRole(op, suffix, apis); err != nil { return err @@ -1107,7 +1107,7 @@ func csvCopyPrototype(src, dst *v1alpha1.ClusterServiceVersion) { Status: src.Status, } for k, v := range src.Annotations { - if k == v1.OperatorGroupTargetsAnnotationKey { + if k == operatorsv1.OperatorGroupTargetsAnnotationKey { continue } if k == "kubectl.kubernetes.io/last-applied-configuration" { diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go b/staging/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go index b8e255f0da..fe5afe6e9d 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/operatorcondition_controller.go @@ -8,7 +8,7 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" meta "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -147,7 +147,7 @@ func (r *OperatorConditionReconciler) ensureOperatorConditionRole(operatorCondit existingRole := &rbacv1.Role{} err := r.Client.Get(context.TODO(), client.ObjectKey{Name: role.GetName(), Namespace: role.GetNamespace()}, existingRole) if err != nil { - if !k8serrors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return err } return r.Client.Create(context.TODO(), role) @@ -193,7 +193,7 @@ func (r *OperatorConditionReconciler) ensureOperatorConditionRoleBinding(operato existingRoleBinding := &rbacv1.RoleBinding{} err := r.Client.Get(context.TODO(), client.ObjectKey{Name: roleBinding.GetName(), Namespace: roleBinding.GetNamespace()}, existingRoleBinding) if err != nil { - if !k8serrors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return err } return r.Client.Create(context.TODO(), roleBinding) diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/operatorconditiongenerator_controller.go b/staging/operator-lifecycle-manager/pkg/controller/operators/operatorconditiongenerator_controller.go index 8e37cd44aa..e78ee0321e 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/operatorconditiongenerator_controller.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/operatorconditiongenerator_controller.go @@ -5,7 +5,7 @@ import ( "reflect" "github.com/go-logr/logr" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" @@ -156,7 +156,7 @@ func (r *OperatorConditionGeneratorReconciler) ensureOperatorCondition(operatorC existingOperatorCondition := &operatorsv2.OperatorCondition{} err := r.Client.Get(context.TODO(), client.ObjectKey{Name: operatorCondition.GetName(), Namespace: operatorCondition.GetNamespace()}, existingOperatorCondition) if err != nil { - if !k8serrors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return err } return r.Client.Create(context.TODO(), &operatorCondition) diff --git a/staging/operator-lifecycle-manager/pkg/controller/operators/operatorconditiongenerator_controller_test.go b/staging/operator-lifecycle-manager/pkg/controller/operators/operatorconditiongenerator_controller_test.go index e3d3584b72..122ff5e927 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/operators/operatorconditiongenerator_controller_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/operators/operatorconditiongenerator_controller_test.go @@ -8,7 +8,7 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -147,7 +147,7 @@ var _ = Describe("The OperatorConditionsGenerator Controller", func() { time.Sleep(time.Second * 10) err := k8sClient.Get(ctx, namespacedName, operatorCondition) Expect(err).ToNot(BeNil()) - Expect(k8serrors.IsNotFound(err)).To(BeTrue()) + Expect(apierrors.IsNotFound(err)).To(BeTrue()) }) It("creates an OperatorCondition for a CSV with multiple ServiceAccounts and Deployments", func() { diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap.go b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap.go index 08c9b4d4bf..0f8518d4c5 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/configmap.go @@ -7,9 +7,9 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" - v1 "k8s.io/api/core/v1" + corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/intstr" @@ -64,7 +64,7 @@ func (s *configMapCatalogSourceDecorator) Annotations() map[string]string { return s.GetAnnotations() } -func (s *configMapCatalogSourceDecorator) ConfigMapChanges(configMap *v1.ConfigMap) bool { +func (s *configMapCatalogSourceDecorator) ConfigMapChanges(configMap *corev1.ConfigMap) bool { if s.Status.ConfigMapResource == nil { return true } @@ -74,14 +74,14 @@ func (s *configMapCatalogSourceDecorator) ConfigMapChanges(configMap *v1.ConfigM return true } -func (s *configMapCatalogSourceDecorator) Service() *v1.Service { - svc := &v1.Service{ +func (s *configMapCatalogSourceDecorator) Service() *corev1.Service { + svc := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: s.GetName(), Namespace: s.GetNamespace(), }, - Spec: v1.ServiceSpec{ - Ports: []v1.ServicePort{ + Spec: corev1.ServiceSpec{ + Ports: []corev1.ServicePort{ { Name: "grpc", Port: 50051, @@ -100,7 +100,7 @@ func (s *configMapCatalogSourceDecorator) Service() *v1.Service { return svc } -func (s *configMapCatalogSourceDecorator) Pod(image string) *v1.Pod { +func (s *configMapCatalogSourceDecorator) Pod(image string) *corev1.Pod { pod := Pod(s.CatalogSource, "configmap-registry-server", image, "", s.Labels(), s.Annotations(), 5, 5) pod.Spec.ServiceAccountName = s.GetName() + ConfigMapServerPostfix pod.Spec.Containers[0].Command = []string{"configmap-server", "-c", s.Spec.ConfigMap, "-n", s.GetNamespace()} @@ -108,8 +108,8 @@ func (s *configMapCatalogSourceDecorator) Pod(image string) *v1.Pod { return pod } -func (s *configMapCatalogSourceDecorator) ServiceAccount() *v1.ServiceAccount { - sa := &v1.ServiceAccount{ +func (s *configMapCatalogSourceDecorator) ServiceAccount() *corev1.ServiceAccount { + sa := &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: s.serviceAccountName(), Namespace: s.GetNamespace(), @@ -172,7 +172,7 @@ var _ RegistryEnsurer = &ConfigMapRegistryReconciler{} var _ RegistryChecker = &ConfigMapRegistryReconciler{} var _ RegistryReconciler = &ConfigMapRegistryReconciler{} -func (c *ConfigMapRegistryReconciler) currentService(source configMapCatalogSourceDecorator) *v1.Service { +func (c *ConfigMapRegistryReconciler) currentService(source configMapCatalogSourceDecorator) *corev1.Service { serviceName := source.Service().GetName() service, err := c.Lister.CoreV1().ServiceLister().Services(source.GetNamespace()).Get(serviceName) if err != nil { @@ -182,7 +182,7 @@ func (c *ConfigMapRegistryReconciler) currentService(source configMapCatalogSour return service } -func (c *ConfigMapRegistryReconciler) currentServiceAccount(source configMapCatalogSourceDecorator) *v1.ServiceAccount { +func (c *ConfigMapRegistryReconciler) currentServiceAccount(source configMapCatalogSourceDecorator) *corev1.ServiceAccount { serviceAccountName := source.ServiceAccount().GetName() serviceAccount, err := c.Lister.CoreV1().ServiceAccountLister().ServiceAccounts(source.GetNamespace()).Get(serviceAccountName) if err != nil { @@ -212,7 +212,7 @@ func (c *ConfigMapRegistryReconciler) currentRoleBinding(source configMapCatalog return roleBinding } -func (c *ConfigMapRegistryReconciler) currentPods(source configMapCatalogSourceDecorator, image string) []*v1.Pod { +func (c *ConfigMapRegistryReconciler) currentPods(source configMapCatalogSourceDecorator, image string) []*corev1.Pod { podName := source.Pod(image).GetName() pods, err := c.Lister.CoreV1().PodLister().Pods(source.GetNamespace()).List(labels.SelectorFromSet(source.Selector())) if err != nil { @@ -225,7 +225,7 @@ func (c *ConfigMapRegistryReconciler) currentPods(source configMapCatalogSourceD return pods } -func (c *ConfigMapRegistryReconciler) currentPodsWithCorrectResourceVersion(source configMapCatalogSourceDecorator, image string) []*v1.Pod { +func (c *ConfigMapRegistryReconciler) currentPodsWithCorrectResourceVersion(source configMapCatalogSourceDecorator, image string) []*corev1.Pod { podName := source.Pod(image).GetName() pods, err := c.Lister.CoreV1().PodLister().Pods(source.GetNamespace()).List(labels.SelectorFromValidatedSet(source.Labels())) if err != nil { @@ -316,7 +316,7 @@ func (c *ConfigMapRegistryReconciler) ensureServiceAccount(source configMapCatal if !overwrite { return nil } - if err := c.OpClient.DeleteServiceAccount(serviceAccount.GetNamespace(), serviceAccount.GetName(), metav1.NewDeleteOptions(0)); err != nil && !k8serrors.IsNotFound(err) { + if err := c.OpClient.DeleteServiceAccount(serviceAccount.GetNamespace(), serviceAccount.GetName(), metav1.NewDeleteOptions(0)); err != nil && !apierrors.IsNotFound(err) { return err } } @@ -330,7 +330,7 @@ func (c *ConfigMapRegistryReconciler) ensureRole(source configMapCatalogSourceDe if !overwrite { return nil } - if err := c.OpClient.DeleteRole(role.GetNamespace(), role.GetName(), metav1.NewDeleteOptions(0)); err != nil && !k8serrors.IsNotFound(err) { + if err := c.OpClient.DeleteRole(role.GetNamespace(), role.GetName(), metav1.NewDeleteOptions(0)); err != nil && !apierrors.IsNotFound(err) { return err } } @@ -344,7 +344,7 @@ func (c *ConfigMapRegistryReconciler) ensureRoleBinding(source configMapCatalogS if !overwrite { return nil } - if err := c.OpClient.DeleteRoleBinding(roleBinding.GetNamespace(), roleBinding.GetName(), metav1.NewDeleteOptions(0)); err != nil && !k8serrors.IsNotFound(err) { + if err := c.OpClient.DeleteRoleBinding(roleBinding.GetNamespace(), roleBinding.GetName(), metav1.NewDeleteOptions(0)); err != nil && !apierrors.IsNotFound(err) { return err } } @@ -360,7 +360,7 @@ func (c *ConfigMapRegistryReconciler) ensurePod(source configMapCatalogSourceDec return nil } for _, p := range currentPods { - if err := c.OpClient.KubernetesInterface().CoreV1().Pods(pod.GetNamespace()).Delete(context.TODO(), p.GetName(), *metav1.NewDeleteOptions(1)); err != nil && !k8serrors.IsNotFound(err) { + if err := c.OpClient.KubernetesInterface().CoreV1().Pods(pod.GetNamespace()).Delete(context.TODO(), p.GetName(), *metav1.NewDeleteOptions(1)); err != nil && !apierrors.IsNotFound(err) { return errors.Wrapf(err, "error deleting old pod: %s", p.GetName()) } } @@ -379,7 +379,7 @@ func (c *ConfigMapRegistryReconciler) ensureService(source configMapCatalogSourc if !overwrite && ServiceHashMatch(svc, service) { return nil } - if err := c.OpClient.DeleteService(service.GetNamespace(), service.GetName(), metav1.NewDeleteOptions(0)); err != nil && !k8serrors.IsNotFound(err) { + if err := c.OpClient.DeleteService(service.GetNamespace(), service.GetName(), metav1.NewDeleteOptions(0)); err != nil && !apierrors.IsNotFound(err) { return err } } diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc.go b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc.go index 2e50268e12..6da3b58aa1 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc.go @@ -9,7 +9,7 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" - k8serror "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/intstr" @@ -198,7 +198,7 @@ func (c *GrpcRegistryReconciler) EnsureRegistryServer(catalogSource *v1alpha1.Ca // recreate the pod if no existing pod is serving the latest image or correct spec overwritePod := overwrite || len(c.currentPodsWithCorrectImageAndSpec(source, sa.GetName())) == 0 - if err != nil && !k8serror.IsAlreadyExists(err) { + if err != nil && !apierrors.IsAlreadyExists(err) { return errors.Wrapf(err, "error ensuring service account: %s", source.GetName()) } if err := c.ensurePod(source, sa.GetName(), overwritePod); err != nil { @@ -251,7 +251,7 @@ func (c *GrpcRegistryReconciler) ensurePod(source grpcCatalogSourceDecorator, sa return nil } for _, p := range currentLivePods { - if err := c.OpClient.KubernetesInterface().CoreV1().Pods(source.GetNamespace()).Delete(context.TODO(), p.GetName(), *metav1.NewDeleteOptions(1)); err != nil && !k8serror.IsNotFound(err) { + if err := c.OpClient.KubernetesInterface().CoreV1().Pods(source.GetNamespace()).Delete(context.TODO(), p.GetName(), *metav1.NewDeleteOptions(1)); err != nil && !apierrors.IsNotFound(err) { return errors.Wrapf(err, "error deleting old pod: %s", p.GetName()) } } @@ -333,7 +333,7 @@ func (c *GrpcRegistryReconciler) ensureService(source grpcCatalogSourceDecorator return nil } // TODO(tflannag): Do we care about force deleting services? - if err := c.OpClient.DeleteService(service.GetNamespace(), service.GetName(), metav1.NewDeleteOptions(0)); err != nil && !k8serror.IsNotFound(err) { + if err := c.OpClient.DeleteService(service.GetNamespace(), service.GetName(), metav1.NewDeleteOptions(0)); err != nil && !apierrors.IsNotFound(err) { return err } } @@ -428,7 +428,7 @@ func imageID(pod *corev1.Pod) string { func (c *GrpcRegistryReconciler) removePods(pods []*corev1.Pod, namespace string) error { for _, p := range pods { - if err := c.OpClient.KubernetesInterface().CoreV1().Pods(namespace).Delete(context.TODO(), p.GetName(), *metav1.NewDeleteOptions(1)); err != nil && !k8serror.IsNotFound(err) { + if err := c.OpClient.KubernetesInterface().CoreV1().Pods(namespace).Delete(context.TODO(), p.GetName(), *metav1.NewDeleteOptions(1)); err != nil && !apierrors.IsNotFound(err) { return errors.Wrapf(err, "error deleting pod: %s", p.GetName()) } } diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc_test.go b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc_test.go index ef55a856d1..23135185a9 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc_test.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/grpc_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -360,7 +360,7 @@ func TestGrpcRegistryReconciler(t *testing.T) { require.NoError(t, podErr) require.Len(t, outPods.Items, 0) require.NoError(t, err) - require.True(t, k8serrors.IsNotFound(serviceErr)) + require.True(t, apierrors.IsNotFound(serviceErr)) } }) } diff --git a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler.go b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler.go index 050e20d07d..37aec2fa0c 100644 --- a/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler.go +++ b/staging/operator-lifecycle-manager/pkg/controller/registry/reconciler/reconciler.go @@ -6,12 +6,12 @@ import ( "hash/fnv" "strings" - v1 "k8s.io/api/core/v1" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/rand" - "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" controllerclient "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/controller-runtime/client" hashutil "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/util/hash" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient" @@ -32,13 +32,13 @@ const ( // RegistryEnsurer describes methods for ensuring a registry exists. type RegistryEnsurer interface { // EnsureRegistryServer ensures a registry server exists for the given CatalogSource. - EnsureRegistryServer(catalogSource *v1alpha1.CatalogSource) error + EnsureRegistryServer(catalogSource *operatorsv1alpha1.CatalogSource) error } // RegistryChecker describes methods for checking a registry. type RegistryChecker interface { // CheckRegistryServer returns true if the given CatalogSource is considered healthy; false otherwise. - CheckRegistryServer(catalogSource *v1alpha1.CatalogSource) (healthy bool, err error) + CheckRegistryServer(catalogSource *operatorsv1alpha1.CatalogSource) (healthy bool, err error) } // RegistryReconciler knows how to reconcile a registry. @@ -49,7 +49,7 @@ type RegistryReconciler interface { // RegistryReconcilerFactory describes factory methods for RegistryReconcilers. type RegistryReconcilerFactory interface { - ReconcilerForSource(source *v1alpha1.CatalogSource) RegistryReconciler + ReconcilerForSource(source *operatorsv1alpha1.CatalogSource) RegistryReconciler } // RegistryReconcilerFactory is a factory for RegistryReconcilers. @@ -62,17 +62,17 @@ type registryReconcilerFactory struct { } // ReconcilerForSource returns a RegistryReconciler based on the configuration of the given CatalogSource. -func (r *registryReconcilerFactory) ReconcilerForSource(source *v1alpha1.CatalogSource) RegistryReconciler { +func (r *registryReconcilerFactory) ReconcilerForSource(source *operatorsv1alpha1.CatalogSource) RegistryReconciler { // TODO: add memoization by source type switch source.Spec.SourceType { - case v1alpha1.SourceTypeInternal, v1alpha1.SourceTypeConfigmap: + case operatorsv1alpha1.SourceTypeInternal, operatorsv1alpha1.SourceTypeConfigmap: return &ConfigMapRegistryReconciler{ now: r.now, Lister: r.Lister, OpClient: r.OpClient, Image: r.ConfigMapServerImage, } - case v1alpha1.SourceTypeGrpc: + case operatorsv1alpha1.SourceTypeGrpc: if source.Spec.Image != "" { return &GrpcRegistryReconciler{ now: r.now, @@ -100,66 +100,66 @@ func NewRegistryReconcilerFactory(lister operatorlister.OperatorLister, opClient } } -func Pod(source *v1alpha1.CatalogSource, name string, image string, saName string, labels map[string]string, annotations map[string]string, readinessDelay int32, livenessDelay int32) *v1.Pod { +func Pod(source *operatorsv1alpha1.CatalogSource, name string, image string, saName string, labels map[string]string, annotations map[string]string, readinessDelay int32, livenessDelay int32) *corev1.Pod { // Ensure the catalog image is always pulled if the image is not based on a digest, measured by whether an "@" is included. // See https://github.com/docker/distribution/blob/master/reference/reference.go for more info. // This means recreating non-digest based catalog pods will result in the latest version of the catalog content being delivered on-cluster. - var pullPolicy v1.PullPolicy + var pullPolicy corev1.PullPolicy if strings.Contains(image, "@") { - pullPolicy = v1.PullIfNotPresent + pullPolicy = corev1.PullIfNotPresent } else { - pullPolicy = v1.PullAlways + pullPolicy = corev1.PullAlways } readOnlyRootFilesystem := false - pod := &v1.Pod{ + pod := &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ GenerateName: source.GetName() + "-", Namespace: source.GetNamespace(), Labels: labels, Annotations: annotations, }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ { Name: name, Image: image, - Ports: []v1.ContainerPort{ + Ports: []corev1.ContainerPort{ { Name: "grpc", ContainerPort: 50051, }, }, - ReadinessProbe: &v1.Probe{ - ProbeHandler: v1.ProbeHandler{ - Exec: &v1.ExecAction{ + ReadinessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + Exec: &corev1.ExecAction{ Command: []string{"grpc_health_probe", "-addr=:50051"}, }, }, InitialDelaySeconds: readinessDelay, TimeoutSeconds: 5, }, - LivenessProbe: &v1.Probe{ - ProbeHandler: v1.ProbeHandler{ - Exec: &v1.ExecAction{ + LivenessProbe: &corev1.Probe{ + ProbeHandler: corev1.ProbeHandler{ + Exec: &corev1.ExecAction{ Command: []string{"grpc_health_probe", "-addr=:50051"}, }, }, InitialDelaySeconds: livenessDelay, TimeoutSeconds: 5, }, - Resources: v1.ResourceRequirements{ - Requests: v1.ResourceList{ - v1.ResourceCPU: resource.MustParse("10m"), - v1.ResourceMemory: resource.MustParse("50Mi"), + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("10m"), + corev1.ResourceMemory: resource.MustParse("50Mi"), }, }, - SecurityContext: &v1.SecurityContext{ + SecurityContext: &corev1.SecurityContext{ ReadOnlyRootFilesystem: &readOnlyRootFilesystem, }, ImagePullPolicy: pullPolicy, - TerminationMessagePolicy: v1.TerminationMessageFallbackToLogsOnError, + TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError, }, }, NodeSelector: map[string]string{ @@ -188,7 +188,7 @@ func Pod(source *v1alpha1.CatalogSource, name string, image string, saName strin // Override tolerations if grpcPodConfig.Tolerations != nil { - pod.Spec.Tolerations = make([]v1.Toleration, len(grpcPodConfig.Tolerations)) + pod.Spec.Tolerations = make([]corev1.Toleration, len(grpcPodConfig.Tolerations)) for index, toleration := range grpcPodConfig.Tolerations { pod.Spec.Tolerations[index] = *toleration.DeepCopy() } @@ -211,7 +211,7 @@ func Pod(source *v1alpha1.CatalogSource, name string, image string, saName strin } // hashPodSpec calculates a hash given a copy of the pod spec -func hashPodSpec(spec v1.PodSpec) string { +func hashPodSpec(spec corev1.PodSpec) string { hasher := fnv.New32a() hashutil.DeepHashObject(hasher, &spec) return rand.SafeEncodeString(fmt.Sprint(hasher.Sum32())) diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorstatus/clusteroperatorwriter.go b/staging/operator-lifecycle-manager/pkg/lib/operatorstatus/clusteroperatorwriter.go index 2c8928449c..fa566d2564 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorstatus/clusteroperatorwriter.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorstatus/clusteroperatorwriter.go @@ -7,7 +7,7 @@ import ( configv1 "github.com/openshift/api/config/v1" configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/discovery" @@ -36,7 +36,7 @@ func (w *Writer) EnsureExists(name string) (existing *configv1.ClusterOperator, return } - if !k8serrors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return } diff --git a/staging/operator-lifecycle-manager/pkg/lib/operatorstatus/status.go b/staging/operator-lifecycle-manager/pkg/lib/operatorstatus/status.go index 003cb97e8e..4067392c6e 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/operatorstatus/status.go +++ b/staging/operator-lifecycle-manager/pkg/lib/operatorstatus/status.go @@ -12,7 +12,7 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/diff" @@ -88,7 +88,7 @@ func MonitorClusterStatus(name string, syncCh <-chan error, stopCh <-chan struct // create the cluster operator in an initial state if it does not exist existing, err := configClient.ClusterOperators().Get(context.TODO(), name, metav1.GetOptions{}) - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { log.Info("Existing operator status not found, creating") created, createErr := configClient.ClusterOperators().Create(context.TODO(), &configv1.ClusterOperator{ ObjectMeta: metav1.ObjectMeta{ diff --git a/staging/operator-lifecycle-manager/pkg/lib/proxy/syncer.go b/staging/operator-lifecycle-manager/pkg/lib/proxy/syncer.go index 936fbc4f86..b31df18bc9 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/proxy/syncer.go +++ b/staging/operator-lifecycle-manager/pkg/lib/proxy/syncer.go @@ -11,7 +11,7 @@ import ( listers "github.com/openshift/client-go/config/listers/config/v1" "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/client-go/discovery" ) @@ -49,7 +49,7 @@ type Syncer struct { func (w *Syncer) QueryProxyConfig() (proxy []corev1.EnvVar, err error) { global, getErr := w.lister.Get(globalProxyName) if getErr != nil { - if !k8serrors.IsNotFound(getErr) { + if !apierrors.IsNotFound(getErr) { err = getErr return } diff --git a/staging/operator-lifecycle-manager/pkg/lib/scoped/syncer.go b/staging/operator-lifecycle-manager/pkg/lib/scoped/syncer.go index 68d7e42afc..140280dbb3 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/scoped/syncer.go +++ b/staging/operator-lifecycle-manager/pkg/lib/scoped/syncer.go @@ -7,7 +7,7 @@ import ( "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" meta "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -79,7 +79,7 @@ func (s *UserDefinedServiceAccountSyncer) SyncOperatorGroup(in *v1.OperatorGroup // A service account has been specified, we need to update the status. sa, err := s.client.KubernetesInterface().CoreV1().ServiceAccounts(namespace).Get(context.TODO(), serviceAccountName, metav1.GetOptions{}) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { // Set OG's status condition to indicate SA is not found cond := metav1.Condition{ Type: v1.OperatorGroupServiceAccountCondition, diff --git a/staging/operator-lifecycle-manager/pkg/lib/scoped/token_retriever.go b/staging/operator-lifecycle-manager/pkg/lib/scoped/token_retriever.go index 9a1ae12830..bcefb235bb 100644 --- a/staging/operator-lifecycle-manager/pkg/lib/scoped/token_retriever.go +++ b/staging/operator-lifecycle-manager/pkg/lib/scoped/token_retriever.go @@ -7,7 +7,7 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient" "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -54,7 +54,7 @@ func getAPISecret(logger logrus.FieldLogger, kubeclient operatorclient.ClientInt // corev1.ObjectReference only has Name populated. secret, getErr := kubeclient.KubernetesInterface().CoreV1().Secrets(sa.GetNamespace()).Get(context.TODO(), ref.Name, metav1.GetOptions{}) if getErr != nil { - if k8serrors.IsNotFound(getErr) { + if apierrors.IsNotFound(getErr) { logger.Warnf("skipping secret %s - %v", ref.Name, getErr) continue } diff --git a/staging/operator-lifecycle-manager/pkg/metrics/metrics.go b/staging/operator-lifecycle-manager/pkg/metrics/metrics.go index bbb17b00b0..4bb2f4ae8a 100644 --- a/staging/operator-lifecycle-manager/pkg/metrics/metrics.go +++ b/staging/operator-lifecycle-manager/pkg/metrics/metrics.go @@ -8,7 +8,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" - olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" v1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/listers/operators/v1alpha1" ) @@ -246,19 +246,19 @@ func DeleteCatalogSourceStateMetric(name, namespace string) { catalogSourceReady.DeleteLabelValues(namespace, name) } -func DeleteCSVMetric(oldCSV *olmv1alpha1.ClusterServiceVersion) { +func DeleteCSVMetric(oldCSV *operatorsv1alpha1.ClusterServiceVersion) { // Delete the old CSV metrics csvAbnormal.DeleteLabelValues(oldCSV.Namespace, oldCSV.Name, oldCSV.Spec.Version.String(), string(oldCSV.Status.Phase), string(oldCSV.Status.Reason)) csvSucceeded.DeleteLabelValues(oldCSV.Namespace, oldCSV.Name, oldCSV.Spec.Version.String()) } -func EmitCSVMetric(oldCSV *olmv1alpha1.ClusterServiceVersion, newCSV *olmv1alpha1.ClusterServiceVersion) { +func EmitCSVMetric(oldCSV *operatorsv1alpha1.ClusterServiceVersion, newCSV *operatorsv1alpha1.ClusterServiceVersion) { if oldCSV == nil || newCSV == nil { return } // Don't update the metric for copies - if newCSV.Status.Reason == olmv1alpha1.CSVReasonCopied { + if newCSV.Status.Reason == operatorsv1alpha1.CSVReasonCopied { return } @@ -268,7 +268,7 @@ func EmitCSVMetric(oldCSV *olmv1alpha1.ClusterServiceVersion, newCSV *olmv1alpha // Get the phase of the new CSV newCSVPhase := string(newCSV.Status.Phase) csvSucceededGauge := csvSucceeded.WithLabelValues(newCSV.Namespace, newCSV.Name, newCSV.Spec.Version.String()) - if newCSVPhase == string(olmv1alpha1.CSVPhaseSucceeded) { + if newCSVPhase == string(operatorsv1alpha1.CSVPhaseSucceeded) { csvSucceededGauge.Set(1) } else { csvSucceededGauge.Set(0) @@ -276,7 +276,7 @@ func EmitCSVMetric(oldCSV *olmv1alpha1.ClusterServiceVersion, newCSV *olmv1alpha } } -func EmitSubMetric(sub *olmv1alpha1.Subscription) { +func EmitSubMetric(sub *operatorsv1alpha1.Subscription) { if sub.Spec == nil { return } @@ -291,14 +291,14 @@ func EmitSubMetric(sub *olmv1alpha1.Subscription) { } } -func DeleteSubsMetric(sub *olmv1alpha1.Subscription) { +func DeleteSubsMetric(sub *operatorsv1alpha1.Subscription) { if sub.Spec == nil { return } SubscriptionSyncCount.DeleteLabelValues(sub.GetName(), sub.Status.InstalledCSV, sub.Spec.Channel, sub.Spec.Package, string(sub.Spec.InstallPlanApproval)) } -func UpdateSubsSyncCounterStorage(sub *olmv1alpha1.Subscription) { +func UpdateSubsSyncCounterStorage(sub *operatorsv1alpha1.Subscription) { if sub.Spec == nil { return } diff --git a/staging/operator-lifecycle-manager/pkg/package-server/storage/reststorage.go b/staging/operator-lifecycle-manager/pkg/package-server/storage/reststorage.go index f913710697..97f2b205de 100644 --- a/staging/operator-lifecycle-manager/pkg/package-server/storage/reststorage.go +++ b/staging/operator-lifecycle-manager/pkg/package-server/storage/reststorage.go @@ -8,7 +8,7 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/printers" printerstorage "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/printers/storage" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metainternalversion "k8s.io/apimachinery/pkg/apis/meta/internalversion" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -76,7 +76,7 @@ func (m *PackageManifestStorage) List(ctx context.Context, options *metainternal res, err := m.prov.List(namespace, labelSelector) if err != nil { - return nil, k8serrors.NewInternalError(err) + return nil, apierrors.NewInternalError(err) } filtered := []operators.PackageManifest{} @@ -101,7 +101,7 @@ func (m *PackageManifestStorage) Get(ctx context.Context, name string, opts *met namespace := genericreq.NamespaceValue(ctx) manifest, err := m.prov.Get(namespace, name) if err != nil || manifest == nil { - return nil, k8serrors.NewNotFound(m.groupResource, name) + return nil, apierrors.NewNotFound(m.groupResource, name) } // Strip logo icons for i := range manifest.Status.Channels { diff --git a/staging/operator-lifecycle-manager/test/e2e/bundle_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/bundle_e2e_test.go index 6c3791d482..b8c5af8dc1 100644 --- a/staging/operator-lifecycle-manager/test/e2e/bundle_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/bundle_e2e_test.go @@ -8,7 +8,7 @@ import ( "github.com/ghodss/yaml" corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" . "github.com/onsi/ginkgo" @@ -73,7 +73,7 @@ var _ = Describe("Installing bundles with new object types", func() { Eventually(func() error { err := ctx.Ctx().Client().Create(context.Background(), &vpaCRD) if err != nil { - if !k8serrors.IsAlreadyExists(err) { + if !apierrors.IsAlreadyExists(err) { return err } } @@ -167,7 +167,7 @@ var _ = Describe("Installing bundles with new object types", func() { By("Deleting the VPA CRD") Eventually(func() error { err := ctx.Ctx().Client().Delete(context.Background(), &vpaCRD) - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return nil } return err diff --git a/staging/operator-lifecycle-manager/test/e2e/catalog_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/catalog_e2e_test.go index eff0aeab50..ac14002c4a 100644 --- a/staging/operator-lifecycle-manager/test/e2e/catalog_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/catalog_e2e_test.go @@ -12,6 +12,8 @@ import ( "time" operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" + k8serror "k8s.io/apimachinery/pkg/api/errors" + "sigs.k8s.io/controller-runtime/pkg/client" "github.com/blang/semver/v4" . "github.com/onsi/ginkgo" @@ -78,9 +80,18 @@ var _ = Describe("Catalog represents a store of bundles which OLM can use to ins }, } - crd := newCRD(genName("ins")) + crd := newCRD(genName("ins-")) csv := newCSV(packageStable, ns.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd}, nil, nil) + defer func() { + Eventually(func() error { + return ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), crd.GetName(), metav1.DeleteOptions{}) + }).Should(Or(Succeed(), WithTransform(k8serror.IsNotFound, BeTrue()))) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.TODO(), &csv)) + }).Should(Succeed()) + }() + catalogSourceName := genName("mock-ocs-") _, cleanupSource := createInternalCatalogSource(c, crc, catalogSourceName, ns.GetName(), manifests, []apiextensions.CustomResourceDefinition{crd}, []v1alpha1.ClusterServiceVersion{csv}) defer cleanupSource() @@ -138,6 +149,18 @@ var _ = Describe("Catalog represents a store of bundles which OLM can use to ins mainCSV := newCSV(mainPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, nil) replacementCSV := newCSV(mainPackageReplacement, ns.GetName(), mainPackageStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, nil) + defer func() { + Eventually(func() error { + return ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), mainCRD.GetName(), metav1.DeleteOptions{}) + }).Should(Or(Succeed(), WithTransform(k8serror.IsNotFound, BeTrue()))) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.TODO(), &mainCSV)) + }).Should(Succeed()) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.TODO(), &replacementCSV)) + }).Should(Succeed()) + }() + mainCatalogName := genName("mock-ocs-main-") // Create separate manifests for each CatalogSource @@ -230,6 +253,18 @@ var _ = Describe("Catalog represents a store of bundles which OLM can use to ins mainCSV := newCSV(mainPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), nil, []apiextensions.CustomResourceDefinition{dependentCRD}, nil) dependentCSV := newCSV(dependentPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{dependentCRD}, nil, nil) + defer func() { + Eventually(func() error { + return ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), dependentCRD.GetName(), metav1.DeleteOptions{}) + }).Should(Or(Succeed(), WithTransform(k8serror.IsNotFound, BeTrue()))) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.TODO(), &mainCSV)) + }).Should(Succeed()) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.TODO(), &dependentCSV)) + }).Should(Succeed()) + }() + mainCatalogName := genName("mock-ocs-main-") // Create separate manifests for each CatalogSource @@ -351,6 +386,18 @@ var _ = Describe("Catalog represents a store of bundles which OLM can use to ins mainCSV := newCSV(mainPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), nil, []apiextensions.CustomResourceDefinition{dependentCRD}, nil) dependentCSV := newCSV(dependentPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{dependentCRD}, nil, nil) + defer func() { + Eventually(func() error { + return ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), dependentCRD.GetName(), metav1.DeleteOptions{}) + }).Should(Or(Succeed(), WithTransform(k8serror.IsNotFound, BeTrue()))) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.TODO(), &mainCSV)) + }).Should(Succeed()) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.TODO(), &dependentCSV)) + }).Should(Succeed()) + }() + mainCatalogName := genName("mock-ocs-main-") // Create separate manifests for each CatalogSource @@ -433,6 +480,21 @@ var _ = Describe("Catalog represents a store of bundles which OLM can use to ins replacementCSV := newCSV(mainPackageReplacement, ns.GetName(), mainPackageStable, semver.MustParse("0.2.0"), nil, []apiextensions.CustomResourceDefinition{dependentCRD}, nil) dependentCSV := newCSV(dependentPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{dependentCRD}, nil, nil) + defer func() { + Eventually(func() error { + return ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), dependentCRD.GetName(), metav1.DeleteOptions{}) + }).Should(Or(Succeed(), WithTransform(k8serror.IsNotFound, BeTrue()))) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.TODO(), &mainCSV)) + }).Should(Succeed()) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.TODO(), &dependentCSV)) + }).Should(Succeed()) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.TODO(), &replacementCSV)) + }).Should(Succeed()) + }() + mainSourceName := genName("mock-ocs-main-") replacementSourceName := genName("mock-ocs-main-with-replacement-") @@ -565,6 +627,15 @@ var _ = Describe("Catalog represents a store of bundles which OLM can use to ins }, } + defer func() { + Eventually(func() error { + return ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), crd.GetName(), metav1.DeleteOptions{}) + }).Should(Or(Succeed(), WithTransform(k8serror.IsNotFound, BeTrue()))) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.TODO(), &csv)) + }).Should(Succeed()) + }() + _, cleanupSource := createInternalCatalogSource(c, crc, sourceName, ns.GetName(), manifests, []apiextensions.CustomResourceDefinition{crd}, []v1alpha1.ClusterServiceVersion{csv}) defer cleanupSource() diff --git a/staging/operator-lifecycle-manager/test/e2e/copied_csv_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/copied_csv_e2e_test.go new file mode 100644 index 0000000000..6d55c7b24b --- /dev/null +++ b/staging/operator-lifecycle-manager/test/e2e/copied_csv_e2e_test.go @@ -0,0 +1,266 @@ +package e2e + +import ( + "context" + "fmt" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" + operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx" + corev1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" + k8slabels "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" + apitypes "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("Disabling copied CSVs", func() { + var ( + ns corev1.Namespace + csv operatorsv1alpha1.ClusterServiceVersion + nonTerminatingNamespaceSelector = fields.ParseSelectorOrDie("status.phase!=Terminating") + ) + + BeforeEach(func() { + nsname := genName("csv-toggle-test-") + og := operatorsv1.OperatorGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-operatorgroup", nsname), + Namespace: nsname, + }, + } + ns = SetupGeneratedTestNamespaceWithOperatorGroup(nsname, og) + + csv = operatorsv1alpha1.ClusterServiceVersion{ + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv-toggle-test-"), + Namespace: nsname, + }, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + InstallStrategy: newNginxInstallStrategy(genName("csv-toggle-test-"), nil, nil), + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + }, + } + err := ctx.Ctx().Client().Create(context.Background(), &csv) + Expect(err).ShouldNot(HaveOccurred()) + }) + + AfterEach(func() { + Eventually(func() error { + err := ctx.Ctx().Client().Delete(context.Background(), &csv) + if err != nil && k8serrors.IsNotFound(err) { + return err + } + + return nil + }).Should(Succeed()) + TeardownNamespace(ns.GetName()) + }) + + When("an operator is installed in AllNamespace mode", func() { + It("should have Copied CSVs in all other namespaces", func() { + Eventually(func() error { + requirement, err := k8slabels.NewRequirement(operatorsv1alpha1.CopiedLabelKey, selection.Equals, []string{csv.GetNamespace()}) + if err != nil { + return err + } + + var copiedCSVs operatorsv1alpha1.ClusterServiceVersionList + err = ctx.Ctx().Client().List(context.TODO(), &copiedCSVs, &client.ListOptions{ + LabelSelector: k8slabels.NewSelector().Add(*requirement), + }) + if err != nil { + return err + } + + var namespaces corev1.NamespaceList + if err := ctx.Ctx().Client().List(context.TODO(), &namespaces, &client.ListOptions{ + FieldSelector: nonTerminatingNamespaceSelector, + }); err != nil { + return err + } + + if len(namespaces.Items)-1 != len(copiedCSVs.Items) { + return fmt.Errorf("%d copied CSVs found, expected %d", len(copiedCSVs.Items), len(namespaces.Items)-1) + } + + return nil + }).Should(Succeed()) + }) + }) + + When("Copied CSVs are disabled", func() { + BeforeEach(func() { + Eventually(func() error { + var olmConfig operatorsv1.OLMConfig + if err := ctx.Ctx().Client().Get(context.TODO(), apitypes.NamespacedName{Name: "cluster"}, &olmConfig); err != nil { + ctx.Ctx().Logf("Error getting olmConfig %v", err) + return err + } + + // Exit early if copied CSVs are disabled. + if !olmConfig.CopiedCSVsAreEnabled() { + return nil + } + + olmConfig.Spec = operatorsv1.OLMConfigSpec{ + Features: &operatorsv1.Features{ + DisableCopiedCSVs: getPointer(true), + }, + } + + if err := ctx.Ctx().Client().Update(context.TODO(), &olmConfig); err != nil { + ctx.Ctx().Logf("Error setting olmConfig %v", err) + return err + } + + return nil + }).Should(Succeed()) + }) + + It("should not have any copied CSVs", func() { + Eventually(func() error { + requirement, err := k8slabels.NewRequirement(operatorsv1alpha1.CopiedLabelKey, selection.Equals, []string{csv.GetNamespace()}) + if err != nil { + return err + } + + var copiedCSVs operatorsv1alpha1.ClusterServiceVersionList + err = ctx.Ctx().Client().List(context.TODO(), &copiedCSVs, &client.ListOptions{ + LabelSelector: k8slabels.NewSelector().Add(*requirement), + }) + if err != nil { + return err + } + + if numCSVs := len(copiedCSVs.Items); numCSVs != 0 { + return fmt.Errorf("Found %d copied CSVs, should be 0", numCSVs) + } + return nil + }).Should(Succeed()) + }) + + It("should be reflected in the olmConfig.Status.Condition array that the expected number of copied CSVs exist", func() { + Eventually(func() error { + var olmConfig operatorsv1.OLMConfig + if err := ctx.Ctx().Client().Get(context.TODO(), apitypes.NamespacedName{Name: "cluster"}, &olmConfig); err != nil { + return err + } + + foundCondition := meta.FindStatusCondition(olmConfig.Status.Conditions, operatorsv1.DisabledCopiedCSVsConditionType) + if foundCondition == nil { + return fmt.Errorf("%s condition not found", operatorsv1.DisabledCopiedCSVsConditionType) + } + + expectedCondition := metav1.Condition{ + Reason: "NoCopiedCSVsFound", + Message: "Copied CSVs are disabled and none were found for operators installed in AllNamespace mode", + Status: metav1.ConditionTrue, + } + + if foundCondition.Reason != expectedCondition.Reason || + foundCondition.Message != expectedCondition.Message || + foundCondition.Status != expectedCondition.Status { + return fmt.Errorf("condition does not have expected reason, message, and status. Expected %v, got %v", expectedCondition, foundCondition) + } + + return nil + }).Should(Succeed()) + }) + }) + + When("Copied CSVs are toggled back on", func() { + BeforeEach(func() { + Eventually(func() error { + var olmConfig operatorsv1.OLMConfig + if err := ctx.Ctx().Client().Get(context.TODO(), apitypes.NamespacedName{Name: "cluster"}, &olmConfig); err != nil { + return err + } + + // Exit early if copied CSVs are enabled. + if olmConfig.CopiedCSVsAreEnabled() { + return nil + } + + olmConfig.Spec = operatorsv1.OLMConfigSpec{ + Features: &operatorsv1.Features{ + DisableCopiedCSVs: getPointer(false), + }, + } + + if err := ctx.Ctx().Client().Update(context.TODO(), &olmConfig); err != nil { + return err + } + + return nil + }).Should(Succeed()) + }) + + It("should have copied CSVs in all other Namespaces", func() { + Eventually(func() error { + // find copied csvs... + requirement, err := k8slabels.NewRequirement(operatorsv1alpha1.CopiedLabelKey, selection.Equals, []string{csv.GetNamespace()}) + if err != nil { + return err + } + + var copiedCSVs operatorsv1alpha1.ClusterServiceVersionList + err = ctx.Ctx().Client().List(context.TODO(), &copiedCSVs, &client.ListOptions{ + LabelSelector: k8slabels.NewSelector().Add(*requirement), + }) + if err != nil { + return err + } + + var namespaces corev1.NamespaceList + if err := ctx.Ctx().Client().List(context.TODO(), &namespaces, &client.ListOptions{FieldSelector: nonTerminatingNamespaceSelector}); err != nil { + return err + } + + if len(namespaces.Items)-1 != len(copiedCSVs.Items) { + return fmt.Errorf("%d copied CSVs found, expected %d", len(copiedCSVs.Items), len(namespaces.Items)-1) + } + + return nil + }).Should(Succeed()) + }) + + It("should be reflected in the olmConfig.Status.Condition array that the expected number of copied CSVs exist", func() { + Eventually(func() error { + var olmConfig operatorsv1.OLMConfig + if err := ctx.Ctx().Client().Get(context.TODO(), apitypes.NamespacedName{Name: "cluster"}, &olmConfig); err != nil { + return err + } + foundCondition := meta.FindStatusCondition(olmConfig.Status.Conditions, operatorsv1.DisabledCopiedCSVsConditionType) + if foundCondition == nil { + return fmt.Errorf("%s condition not found", operatorsv1.DisabledCopiedCSVsConditionType) + } + + expectedCondition := metav1.Condition{ + Reason: "CopiedCSVsEnabled", + Message: "Copied CSVs are enabled and present across the cluster", + Status: metav1.ConditionFalse, + } + + if foundCondition.Reason != expectedCondition.Reason || + foundCondition.Message != expectedCondition.Message || + foundCondition.Status != expectedCondition.Status { + return fmt.Errorf("condition does not have expected reason, message, and status. Expected %v, got %v", expectedCondition, foundCondition) + } + + return nil + }).Should(Succeed()) + }) + }) +}) diff --git a/staging/operator-lifecycle-manager/test/e2e/crd_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/crd_e2e_test.go index ca1a003125..d14d92d80e 100644 --- a/staging/operator-lifecycle-manager/test/e2e/crd_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/crd_e2e_test.go @@ -15,7 +15,7 @@ import ( "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -487,7 +487,7 @@ var _ = Describe("CRD Versions", func() { Eventually(func() bool { sub, _ := crc.OperatorsV1alpha1().Subscriptions(ns.GetName()).Get(context.TODO(), subscription.GetName(), metav1.GetOptions{}) ip, err := crc.OperatorsV1alpha1().InstallPlans(ns.GetName()).Get(context.TODO(), sub.Status.InstallPlanRef.Name, metav1.GetOptions{}) - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return false } GinkgoT().Logf("waiting for installplan to succeed...currently %s", ip.Status.Phase) diff --git a/staging/operator-lifecycle-manager/test/e2e/csv_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/csv_e2e_test.go index c7ad098797..3b23c6ee66 100644 --- a/staging/operator-lifecycle-manager/test/e2e/csv_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/csv_e2e_test.go @@ -9,22 +9,21 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "github.com/onsi/gomega/types" - + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" + "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" + "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient" + "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/equality" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/meta" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" k8slabels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/selection" - apitypes "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/diff" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/wait" @@ -32,23 +31,14 @@ import ( apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" "sigs.k8s.io/controller-runtime/pkg/client" - operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" - "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned" - "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/install" - "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient" - "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/ownerutil" "github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx" ) var _ = Describe("ClusterServiceVersion", func() { - HavePhase := func(goal operatorsv1alpha1.ClusterServiceVersionPhase) types.GomegaMatcher { - return WithTransform(func(csv *operatorsv1alpha1.ClusterServiceVersion) operatorsv1alpha1.ClusterServiceVersionPhase { - return csv.Status.Phase - }, Equal(goal)) - } var ( + ns corev1.Namespace c operatorclient.ClientInterface crc versioned.Interface ) @@ -59,296 +49,147 @@ var _ = Describe("ClusterServiceVersion", func() { }) AfterEach(func() { - TearDown(testNamespace) + TeardownNamespace(ns.GetName()) }) - When("a CustomResourceDefinition was installed alongside a ClusterServiceVersion", func() { - var ( - ns corev1.Namespace - crd apiextensionsv1.CustomResourceDefinition - og operatorsv1.OperatorGroup - apiname string - apifullname string - ) - + Context("OwnNamespace OperatorGroup", func() { BeforeEach(func() { - ns = corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: genName("test-namespace-"), - }, - } - - Eventually(func() error { - return ctx.Ctx().Client().Create(context.Background(), &ns) - }).Should(Succeed()) - - og = operatorsv1.OperatorGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: genName(fmt.Sprintf("%s-operatorgroup-", ns.GetName())), - Namespace: ns.GetName(), - }, - Spec: operatorsv1.OperatorGroupSpec{ - TargetNamespaces: []string{ns.GetName()}, - }, - } - Eventually(func() error { - return ctx.Ctx().Client().Create(context.Background(), &og) - }).Should(Succeed()) - - apiname = genName("api") - apifullname = apiname + "s.example.com" - crd = apiextensionsv1.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{ - Name: apifullname, - Annotations: map[string]string{ - "operatorframework.io/installed-alongside-0": fmt.Sprintf("%s/associated-csv", ns.GetName()), - }, - }, - Spec: apiextensionsv1.CustomResourceDefinitionSpec{ - Group: "example.com", - Scope: apiextensionsv1.ClusterScoped, - Names: apiextensionsv1.CustomResourceDefinitionNames{ - Plural: apiname + "s", - Singular: apiname, - Kind: strings.Title(apiname), - ListKind: strings.Title(apiname) + "List", - }, - Versions: []apiextensionsv1.CustomResourceDefinitionVersion{{ - Name: "v1", - Served: true, - Storage: true, - Schema: &apiextensionsv1.CustomResourceValidation{ - OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{ - Type: "object", - }, - }, - }}, - }, - } - Eventually(func() error { - return ctx.Ctx().Client().Create(context.Background(), &crd) - }).Should(Succeed()) + nsName := genName("csv-e2e-") + ns = SetupGeneratedTestNamespace(nsName, nsName) }) - AfterEach(func() { - Eventually(func() error { - return ctx.Ctx().Client().Delete(context.Background(), &crd) - }).Should(WithTransform(k8serrors.IsNotFound, BeTrue())) - - Eventually(func() error { - return ctx.Ctx().Client().Delete(context.Background(), &og) - }).Should(WithTransform(k8serrors.IsNotFound, BeTrue())) - - Eventually(func() error { - return ctx.Ctx().Client().Delete(context.Background(), &ns) - }).Should(WithTransform(k8serrors.IsNotFound, BeTrue())) - }) + When("a CustomResourceDefinition was installed alongside a ClusterServiceVersion", func() { + var ( + crd apiextensionsv1.CustomResourceDefinition + apiname string + apifullname string + ) - // issue: https://github.com/operator-framework/operator-lifecycle-manager/issues/2646 - It("[FLAKE] can satisfy an associated ClusterServiceVersion's ownership requirement", func() { - associated := operatorsv1alpha1.ClusterServiceVersion{ - ObjectMeta: metav1.ObjectMeta{ - Name: "associated-csv", - Namespace: ns.GetName(), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{{ - Name: apifullname, - Version: "v1", - Kind: "Test", - }}, - }, - InstallStrategy: newNginxInstallStrategy(genName("deployment-"), nil, nil), - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, + BeforeEach(func() { + apiname = genName("api") + apifullname = apiname + "s.example.com" + crd = apiextensionsv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: apifullname, + Annotations: map[string]string{ + "operatorframework.io/installed-alongside-0": fmt.Sprintf("%s/associated-csv", ns.GetName()), }, }, - }, - } - Expect(ctx.Ctx().Client().Create(context.Background(), &associated)).To(Succeed()) - - Eventually(func() ([]operatorsv1alpha1.RequirementStatus, error) { - if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&associated), &associated); err != nil { - return nil, err - } - var result []operatorsv1alpha1.RequirementStatus - for _, s := range associated.Status.RequirementStatus { - result = append(result, operatorsv1alpha1.RequirementStatus{ - Group: s.Group, - Version: s.Version, - Kind: s.Kind, - Name: s.Name, - Status: s.Status, - }) - } - return result, nil - }).Should(ContainElement( - operatorsv1alpha1.RequirementStatus{ - Group: apiextensionsv1.SchemeGroupVersion.Group, - Version: apiextensionsv1.SchemeGroupVersion.Version, - Kind: "CustomResourceDefinition", - Name: crd.GetName(), - Status: operatorsv1alpha1.RequirementStatusReasonPresent, - }, - )) - - Eventually(func() error { - return ctx.Ctx().Client().Delete(context.Background(), &associated) - }).Should(Succeed()) - }) - - // Without this exception, upgrades can become blocked - // when the original CSV's CRD requirement becomes - // unsatisfied. - It("can satisfy an unassociated ClusterServiceVersion's ownership requirement if replaced by an associated ClusterServiceVersion", func() { - unassociated := operatorsv1alpha1.ClusterServiceVersion{ - ObjectMeta: metav1.ObjectMeta{ - Name: "unassociated-csv", - Namespace: ns.GetName(), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{{ - Name: apifullname, - Version: "v1", - Kind: "Test", - }}, - }, - InstallStrategy: newNginxInstallStrategy(genName("deployment-"), nil, nil), - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, + Spec: apiextensionsv1.CustomResourceDefinitionSpec{ + Group: "example.com", + Scope: apiextensionsv1.ClusterScoped, + Names: apiextensionsv1.CustomResourceDefinitionNames{ + Plural: apiname + "s", + Singular: apiname, + Kind: strings.Title(apiname), + ListKind: strings.Title(apiname) + "List", }, - }, - }, - } - Expect(ctx.Ctx().Client().Create(context.Background(), &unassociated)).To(Succeed()) - - associated := operatorsv1alpha1.ClusterServiceVersion{ - ObjectMeta: metav1.ObjectMeta{ - Name: "associated-csv", - Namespace: ns.GetName(), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{{ - Name: apifullname, - Version: "v1", - Kind: "Test", + Versions: []apiextensionsv1.CustomResourceDefinitionVersion{{ + Name: "v1", + Served: true, + Storage: true, + Schema: &apiextensionsv1.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{ + Type: "object", + }, + }, }}, }, - InstallStrategy: newNginxInstallStrategy(genName("deployment-"), nil, nil), - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - }, - Replaces: unassociated.GetName(), - }, - } - Expect(ctx.Ctx().Client().Create(context.Background(), &associated)).To(Succeed()) - - Eventually(func() error { - return ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&unassociated), &unassociated) - }).Should(WithTransform(k8serrors.IsNotFound, BeTrue())) + } + Eventually(func() error { + return ctx.Ctx().Client().Create(context.Background(), &crd) + }).Should(Succeed()) + }) - Eventually(func() error { - return ctx.Ctx().Client().Delete(context.Background(), &associated) - }).Should(Succeed()) - }) + AfterEach(func() { + Eventually(func() error { + return ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), crd.GetName(), metav1.DeleteOptions{}) + }).Should(Succeed()) + }) - // issue:https://github.com/operator-framework/operator-lifecycle-manager/issues/2639 - It("[FLAKE] can satisfy an unassociated ClusterServiceVersion's non-ownership requirement", func() { - unassociated := operatorsv1alpha1.ClusterServiceVersion{ - ObjectMeta: metav1.ObjectMeta{ - Name: "unassociated-csv", - Namespace: ns.GetName(), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Required: []operatorsv1alpha1.CRDDescription{{ - Name: apifullname, - Version: "v1", - Kind: "Test", - }}, + It("can satisfy an associated ClusterServiceVersion's ownership requirement", func() { + associated := operatorsv1alpha1.ClusterServiceVersion{ + ObjectMeta: metav1.ObjectMeta{ + Name: "associated-csv", + Namespace: ns.GetName(), }, - InstallStrategy: newNginxInstallStrategy(genName("deployment-"), nil, nil), - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{{ + Name: apifullname, + Version: "v1", + Kind: "Test", + }}, + }, + InstallStrategy: newNginxInstallStrategy(genName("deployment-"), nil, nil), + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, }, }, - }, - } - Expect(ctx.Ctx().Client().Create(context.Background(), &unassociated)).To(Succeed()) - - Eventually(func() ([]operatorsv1alpha1.RequirementStatus, error) { - if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&unassociated), &unassociated); err != nil { - return nil, err } - var result []operatorsv1alpha1.RequirementStatus - for _, s := range unassociated.Status.RequirementStatus { - result = append(result, operatorsv1alpha1.RequirementStatus{ - Group: s.Group, - Version: s.Version, - Kind: s.Kind, - Name: s.Name, - Status: s.Status, - }) - } - return result, nil - }).Should(ContainElement( - operatorsv1alpha1.RequirementStatus{ - Group: apiextensionsv1.SchemeGroupVersion.Group, - Version: apiextensionsv1.SchemeGroupVersion.Version, - Kind: "CustomResourceDefinition", - Name: crd.GetName(), - Status: operatorsv1alpha1.RequirementStatusReasonPresent, - }, - )) - Eventually(func() error { - return ctx.Ctx().Client().Delete(context.Background(), &unassociated) - }).Should(Succeed()) - }) - - When("an unassociated ClusterServiceVersion in different namespace owns the same CRD", func() { - var ( - ns corev1.Namespace - ) + Expect(ctx.Ctx().Client().Create(context.Background(), &associated)).To(Succeed()) - BeforeEach(func() { - ns = corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: genName("test-namespace-2-"), + Eventually(func() ([]operatorsv1alpha1.RequirementStatus, error) { + if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&associated), &associated); err != nil { + return nil, err + } + var result []operatorsv1alpha1.RequirementStatus + for _, s := range associated.Status.RequirementStatus { + result = append(result, operatorsv1alpha1.RequirementStatus{ + Group: s.Group, + Version: s.Version, + Kind: s.Kind, + Name: s.Name, + Status: s.Status, + }) + } + return result, nil + }).Should(ContainElement( + operatorsv1alpha1.RequirementStatus{ + Group: apiextensionsv1.SchemeGroupVersion.Group, + Version: apiextensionsv1.SchemeGroupVersion.Version, + Kind: "CustomResourceDefinition", + Name: crd.GetName(), + Status: operatorsv1alpha1.RequirementStatusReasonPresent, }, - } - Expect(ctx.Ctx().Client().Create(context.Background(), &ns)).To(Succeed()) + )) + + Eventually(func() error { + return ctx.Ctx().Client().Delete(context.Background(), &associated) + }).Should(Succeed()) + }) - og = operatorsv1.OperatorGroup{ + // Without this exception, upgrades can become blocked + // when the original CSV's CRD requirement becomes + // unsatisfied. + It("can satisfy an unassociated ClusterServiceVersion's ownership requirement if replaced by an associated ClusterServiceVersion", func() { + unassociated := operatorsv1alpha1.ClusterServiceVersion{ ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-operatorgroup", ns.GetName()), + Name: "unassociated-csv", Namespace: ns.GetName(), }, - Spec: operatorsv1.OperatorGroupSpec{ - TargetNamespaces: []string{ns.GetName()}, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{{ + Name: apifullname, + Version: "v1", + Kind: "Test", + }}, + }, + InstallStrategy: newNginxInstallStrategy(genName("deployment-"), nil, nil), + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + }, }, } - Expect(ctx.Ctx().Client().Create(context.TODO(), &og)).To(Succeed()) - }) - - AfterEach(func() { - Eventually(func() error { - return ctx.Ctx().Client().Delete(context.Background(), &ns) - }).Should(WithTransform(k8serrors.IsNotFound, BeTrue())) - }) + Expect(ctx.Ctx().Client().Create(context.Background(), &unassociated)).To(Succeed()) - It("can satisfy the unassociated ClusterServiceVersion's ownership requirement", func() { associated := operatorsv1alpha1.ClusterServiceVersion{ ObjectMeta: metav1.ObjectMeta{ Name: "associated-csv", @@ -369,10 +210,21 @@ var _ = Describe("ClusterServiceVersion", func() { Supported: true, }, }, + Replaces: unassociated.GetName(), }, } Expect(ctx.Ctx().Client().Create(context.Background(), &associated)).To(Succeed()) + Eventually(func() error { + return ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&unassociated), &unassociated) + }).Should(WithTransform(apierrors.IsNotFound, BeTrue())) + + Eventually(func() error { + return ctx.Ctx().Client().Delete(context.Background(), &associated) + }).Should(Succeed()) + }) + + It("can satisfy an unassociated ClusterServiceVersion's non-ownership requirement", func() { unassociated := operatorsv1alpha1.ClusterServiceVersion{ ObjectMeta: metav1.ObjectMeta{ Name: "unassociated-csv", @@ -380,7 +232,7 @@ var _ = Describe("ClusterServiceVersion", func() { }, Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{{ + Required: []operatorsv1alpha1.CRDDescription{{ Name: apifullname, Version: "v1", Kind: "Test", @@ -421,4043 +273,3914 @@ var _ = Describe("ClusterServiceVersion", func() { Status: operatorsv1alpha1.RequirementStatusReasonPresent, }, )) + Eventually(func() error { + return ctx.Ctx().Client().Delete(context.Background(), &unassociated) + }).Should(Succeed()) }) }) - }) - When("a csv exists specifying two replicas with one max unavailable", func() { - var ( - csv operatorsv1alpha1.ClusterServiceVersion - ) + When("an unassociated ClusterServiceVersion in different namespace owns the same CRD", func() { - const ( - TestReadinessGate = "operatorframework.io/test-readiness-gate" - ) + var ( + crd apiextensionsv1.CustomResourceDefinition + apiname string + apifullname string + ) - BeforeEach(func() { - csv = operatorsv1alpha1.ClusterServiceVersion{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "test-csv", - Namespace: testNamespace, - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: "deployment", - Spec: appsv1.DeploymentSpec{ - Strategy: appsv1.DeploymentStrategy{ - Type: appsv1.RollingUpdateDeploymentStrategyType, - RollingUpdate: &appsv1.RollingUpdateDeployment{ - MaxUnavailable: &[]intstr.IntOrString{intstr.FromInt(1)}[0], - }, - }, - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "foobar"}, - }, - Replicas: &[]int32{2}[0], - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "foobar"}, - }, - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - { - Name: "foobar", - Image: *dummyImage, - }, - }, - ReadinessGates: []corev1.PodReadinessGate{ - {ConditionType: TestReadinessGate}, - }, - }, - }, - }, + BeforeEach(func() { + apiname = genName("api") + apifullname = apiname + "s.example.com" + crd = apiextensionsv1.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: apifullname, + Annotations: map[string]string{ + "operatorframework.io/installed-alongside-0": fmt.Sprintf("%s/associated-csv", ns.GetName()), + }, + }, + Spec: apiextensionsv1.CustomResourceDefinitionSpec{ + Group: "example.com", + Scope: apiextensionsv1.ClusterScoped, + Names: apiextensionsv1.CustomResourceDefinitionNames{ + Plural: apiname + "s", + Singular: apiname, + Kind: strings.Title(apiname), + ListKind: strings.Title(apiname) + "List", + }, + Versions: []apiextensionsv1.CustomResourceDefinitionVersion{{ + Name: "v1", + Served: true, + Storage: true, + Schema: &apiextensionsv1.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{ + Type: "object", }, }, - }, + }}, }, - InstallModes: []operatorsv1alpha1.InstallMode{{ - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }}, - }, - } - Expect(ctx.Ctx().Client().Create(context.Background(), &csv)).To(Succeed()) - - Eventually(func() (*operatorsv1alpha1.ClusterServiceVersion, error) { - var ps corev1.PodList - if err := ctx.Ctx().Client().List(context.Background(), &ps, client.MatchingLabels{"app": "foobar"}); err != nil { - return nil, err - } - - if len(ps.Items) != 2 { - return nil, fmt.Errorf("%d pods match deployment selector, want %d", len(ps.Items), 2) - } - - for _, pod := range ps.Items { - index := -1 - for i, c := range pod.Status.Conditions { - if c.Type == TestReadinessGate { - index = i - break - } - } - if index == -1 { - index = len(pod.Status.Conditions) - pod.Status.Conditions = append(pod.Status.Conditions, corev1.PodCondition{Type: TestReadinessGate}) - } - if pod.Status.Conditions[index].Status == corev1.ConditionTrue { - continue - } - pod.Status.Conditions[index].Status = corev1.ConditionTrue - if err := ctx.Ctx().Client().Status().Update(context.Background(), &pod); err != nil { - return nil, err - } } + Eventually(func() error { + return ctx.Ctx().Client().Create(context.Background(), &crd) + }).Should(Succeed()) + }) - if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&csv), &csv); err != nil { - return nil, err - } - return &csv, nil - }).Should(HavePhase(operatorsv1alpha1.CSVPhaseSucceeded)) - }) + It("can satisfy the unassociated ClusterServiceVersion's ownership requirement", func() { + associated := operatorsv1alpha1.ClusterServiceVersion{ + ObjectMeta: metav1.ObjectMeta{ + Name: "associated-csv", + Namespace: ns.GetName(), + }, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{{ + Name: apifullname, + Version: "v1", + Kind: "Test", + }}, + }, + InstallStrategy: newNginxInstallStrategy(genName("deployment-"), nil, nil), + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + }, + }, + } + Expect(ctx.Ctx().Client().Create(context.Background(), &associated)).To(Succeed()) - It("remains in phase Succeeded when only one pod is available", func() { - Eventually(func() int32 { - dep, err := c.GetDeployment(testNamespace, "deployment") - if err != nil || dep == nil { - return 0 + unassociated := operatorsv1alpha1.ClusterServiceVersion{ + ObjectMeta: metav1.ObjectMeta{ + Name: "unassociated-csv", + Namespace: ns.GetName(), + }, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{{ + Name: apifullname, + Version: "v1", + Kind: "Test", + }}, + }, + InstallStrategy: newNginxInstallStrategy(genName("deployment-"), nil, nil), + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + }, + }, } - return dep.Status.ReadyReplicas - }).Should(Equal(int32(2))) + Expect(ctx.Ctx().Client().Create(context.Background(), &unassociated)).To(Succeed()) - var ps corev1.PodList - Expect(ctx.Ctx().Client().List(context.Background(), &ps, client.MatchingLabels{"app": "foobar"})).To(Succeed()) - Expect(ps.Items).To(Not(BeEmpty())) + Eventually(func() ([]operatorsv1alpha1.RequirementStatus, error) { + if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&unassociated), &unassociated); err != nil { + return nil, err + } + var result []operatorsv1alpha1.RequirementStatus + for _, s := range unassociated.Status.RequirementStatus { + result = append(result, operatorsv1alpha1.RequirementStatus{ + Group: s.Group, + Version: s.Version, + Kind: s.Kind, + Name: s.Name, + Status: s.Status, + }) + } + return result, nil + }).Should(ContainElement( + operatorsv1alpha1.RequirementStatus{ + Group: apiextensionsv1.SchemeGroupVersion.Group, + Version: apiextensionsv1.SchemeGroupVersion.Version, + Kind: "CustomResourceDefinition", + Name: crd.GetName(), + Status: operatorsv1alpha1.RequirementStatusReasonPresent, + }, + )) + }) + }) + }) - Expect(ctx.Ctx().Client().Delete(context.Background(), &ps.Items[0])).To(Succeed()) + Context("AllNamespaces OperatorGroup", func() { + BeforeEach(func() { + ns = SetupGeneratedTestNamespace(genName("csv-e2e-")) + }) + + When("a csv exists specifying two replicas with one max unavailable", func() { + var ( + csv operatorsv1alpha1.ClusterServiceVersion + ) + + const ( + TestReadinessGate = "operatorframework.io/test-readiness-gate" + ) + + BeforeEach(func() { + csv = operatorsv1alpha1.ClusterServiceVersion{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "test-csv", + Namespace: ns.GetName(), + }, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ + { + Name: "deployment", + Spec: appsv1.DeploymentSpec{ + Strategy: appsv1.DeploymentStrategy{ + Type: appsv1.RollingUpdateDeploymentStrategyType, + RollingUpdate: &appsv1.RollingUpdateDeployment{ + MaxUnavailable: &[]intstr.IntOrString{intstr.FromInt(1)}[0], + }, + }, + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "foobar"}, + }, + Replicas: &[]int32{2}[0], + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"app": "foobar"}, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "foobar", + Image: *dummyImage, + }, + }, + ReadinessGates: []corev1.PodReadinessGate{ + {ConditionType: TestReadinessGate}, + }, + }, + }, + }, + }, + }, + }, + }, + InstallModes: []operatorsv1alpha1.InstallMode{{ + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }}, + }, + } + Expect(ctx.Ctx().Client().Create(context.Background(), &csv)).To(Succeed()) + + Eventually(func() (*operatorsv1alpha1.ClusterServiceVersion, error) { + var ps corev1.PodList + if err := ctx.Ctx().Client().List(context.Background(), &ps, client.MatchingLabels{"app": "foobar"}); err != nil { + return nil, err + } + + if len(ps.Items) != 2 { + return nil, fmt.Errorf("%d pods match deployment selector, want %d", len(ps.Items), 2) + } + + for _, pod := range ps.Items { + index := -1 + for i, c := range pod.Status.Conditions { + if c.Type == TestReadinessGate { + index = i + break + } + } + if index == -1 { + index = len(pod.Status.Conditions) + pod.Status.Conditions = append(pod.Status.Conditions, corev1.PodCondition{Type: TestReadinessGate}) + } + if pod.Status.Conditions[index].Status == corev1.ConditionTrue { + continue + } + pod.Status.Conditions[index].Status = corev1.ConditionTrue + if err := ctx.Ctx().Client().Status().Update(context.Background(), &pod); err != nil { + return nil, err + } + } + + if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&csv), &csv); err != nil { + return nil, err + } + return &csv, nil + }).Should(CSVHasPhase(operatorsv1alpha1.CSVPhaseSucceeded)) + }) - Consistently(func() (*operatorsv1alpha1.ClusterServiceVersion, error) { - return &csv, ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&csv), &csv) - }).Should(HavePhase(operatorsv1alpha1.CSVPhaseSucceeded)) + It("remains in phase Succeeded when only one pod is available", func() { + Eventually(func() int32 { + dep, err := c.GetDeployment(ns.GetName(), "deployment") + if err != nil || dep == nil { + return 0 + } + return dep.Status.ReadyReplicas + }).Should(Equal(int32(2))) + + var ps corev1.PodList + Expect(ctx.Ctx().Client().List(context.Background(), &ps, client.MatchingLabels{"app": "foobar"})).To(Succeed()) + Expect(ps.Items).To(Not(BeEmpty())) + + Expect(ctx.Ctx().Client().Delete(context.Background(), &ps.Items[0])).To(Succeed()) + + Consistently(func() (*operatorsv1alpha1.ClusterServiceVersion, error) { + return &csv, ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&csv), &csv) + }).Should(CSVHasPhase(operatorsv1alpha1.CSVPhaseSucceeded)) + }) }) - }) + When("a copied csv exists", func() { + var ( + target corev1.Namespace + original operatorsv1alpha1.ClusterServiceVersion + copyCSV operatorsv1alpha1.ClusterServiceVersion + ) + + BeforeEach(func() { + target = corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "watched-", + }, + } + Expect(ctx.Ctx().Client().Create(context.Background(), &target)).To(Succeed()) + + original = operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "csv-", + Namespace: ns.GetName(), + }, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + InstallStrategy: newNginxInstallStrategy(genName("csv-"), nil, nil), + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + }, + } + Expect(ctx.Ctx().Client().Create(context.Background(), &original)).To(Succeed()) + + Eventually(func() error { + key := client.ObjectKeyFromObject(&original) + key.Namespace = target.GetName() + return ctx.Ctx().Client().Get(context.Background(), key, ©CSV) + }).Should(Succeed()) + }) + + AfterEach(func() { + if target.GetName() != "" { + Expect(ctx.Ctx().Client().Delete(context.Background(), &target)).To(Succeed()) + } + }) + + It("is synchronized with the original csv", func() { + Eventually(func() error { + key := client.ObjectKeyFromObject(©CSV) + + key.Namespace = target.Name + if err := ctx.Ctx().Client().Get(context.Background(), key, ©CSV); err != nil { + return err + } - When("a copied csv exists", func() { - var ( - target corev1.Namespace - original operatorsv1alpha1.ClusterServiceVersion - copy operatorsv1alpha1.ClusterServiceVersion - ) + copyCSV.Status.LastUpdateTime = &metav1.Time{Time: time.Unix(1, 0)} + return ctx.Ctx().Client().Status().Update(context.Background(), ©CSV) + }).Should(Succeed()) + + Eventually(func() (bool, error) { + key := client.ObjectKeyFromObject(&original) + + if err := ctx.Ctx().Client().Get(context.Background(), key, &original); err != nil { + return false, err + } + + key.Namespace = target.Name + if err := ctx.Ctx().Client().Get(context.Background(), key, ©CSV); err != nil { + return false, err + } + + return original.Status.LastUpdateTime.Equal(copyCSV.Status.LastUpdateTime), nil + }).Should(BeTrue(), "Change to status of copy should have been reverted") + }) + }) + When("a csv requires a serviceaccount solely owned by a non-csv", func() { + var ( + cm corev1.ConfigMap + sa corev1.ServiceAccount + csv operatorsv1alpha1.ClusterServiceVersion + ) + + BeforeEach(func() { + cm = corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "cm-", + Namespace: ns.GetName(), + }, + } + Expect(ctx.Ctx().Client().Create(context.Background(), &cm)).To(Succeed()) + + sa = corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "sa-", + Namespace: ns.GetName(), + OwnerReferences: []metav1.OwnerReference{ + { + Name: cm.GetName(), + APIVersion: corev1.SchemeGroupVersion.String(), + Kind: "ConfigMap", + UID: cm.GetUID(), + }, + }, + }, + } + Expect(ctx.Ctx().Client().Create(context.Background(), &sa)).To(Succeed()) + + csv = operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + GenerateName: "csv-", + Namespace: ns.GetName(), + }, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ + { + Name: "foo", + Spec: appsv1.DeploymentSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"app": "foo"}, + }, + Template: corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{"app": "foo"}, + }, + Spec: corev1.PodSpec{Containers: []corev1.Container{ + { + Name: genName("foo"), + Image: *dummyImage, + }, + }}, + }, + }, + }, + }, + Permissions: []operatorsv1alpha1.StrategyDeploymentPermissions{ + { + ServiceAccountName: sa.GetName(), + Rules: []rbacv1.PolicyRule{}, + }, + }, + }, + }, + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + }, + } + Expect(ctx.Ctx().Client().Create(context.Background(), &csv)).To(Succeed()) + }) + + AfterEach(func() { + if cm.GetName() != "" { + Expect(ctx.Ctx().Client().Delete(context.Background(), &cm)).To(Succeed()) + } + }) + + It("considers the serviceaccount requirement satisfied", func() { + Eventually(func() (operatorsv1alpha1.StatusReason, error) { + if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&csv), &csv); err != nil { + return "", err + } + for _, requirement := range csv.Status.RequirementStatus { + if requirement.Name != sa.GetName() { + continue + } + return requirement.Status, nil + } + return "", fmt.Errorf("missing expected requirement %q", sa.GetName()) + }).Should(Equal(operatorsv1alpha1.RequirementStatusReasonPresent)) + }) + }) + + It("create with unmet requirements min kube version", func() { + + depName := genName("dep-") + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), + }, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "999.999.999", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: newNginxInstallStrategy(depName, nil, nil), + }, + } + + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() + + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvPendingChecker) + Expect(err).ShouldNot(HaveOccurred()) + + // Shouldn't create deployment + Consistently(func() bool { + _, err := c.GetDeployment(ns.GetName(), depName) + return apierrors.IsNotFound(err) + }).Should(BeTrue()) + }) + // TODO: same test but missing serviceaccount instead + It("create with unmet requirements CRD", func() { + + depName := genName("dep-") + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), + }, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + + InstallStrategy: newNginxInstallStrategy(depName, nil, nil), + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + DisplayName: "Not In Cluster", + Description: "A CRD that is not currently in the cluster", + Name: "not.in.cluster.com", + Version: "v1alpha1", + Kind: "NotInCluster", + }, + }, + }, + }, + } + + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() + + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvPendingChecker) + Expect(err).ShouldNot(HaveOccurred()) + + // Shouldn't create deployment + Consistently(func() bool { + _, err := c.GetDeployment(ns.GetName(), depName) + return apierrors.IsNotFound(err) + }).Should(BeTrue()) + }) + + It("create with unmet permissions CRD", func() { + saName := genName("dep-") + permissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ + { + ServiceAccountName: saName, + Rules: []rbacv1.PolicyRule{ + { + Verbs: []string{"create"}, + APIGroups: []string{""}, + Resources: []string{"deployment"}, + }, + }, + }, + } - BeforeEach(func() { - target = corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "watched-", + clusterPermissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ + { + ServiceAccountName: saName, + Rules: []rbacv1.PolicyRule{ + { + Verbs: []string{"get"}, + APIGroups: []string{""}, + Resources: []string{"deployment"}, + }, + }, }, } - Expect(ctx.Ctx().Client().Create(context.Background(), &target)).To(Succeed()) - original = operatorsv1alpha1.ClusterServiceVersion{ + crdPlural := genName("ins") + crdName := crdPlural + ".cluster.com" + depName := genName("dep-") + csv := operatorsv1alpha1.ClusterServiceVersion{ TypeMeta: metav1.TypeMeta{ Kind: operatorsv1alpha1.ClusterServiceVersionKind, APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, }, ObjectMeta: metav1.ObjectMeta{ - GenerateName: "csv-", - Namespace: testNamespace, + Name: genName("csv"), }, Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - InstallStrategy: newNginxInstallStrategy(genName("csv-"), nil, nil), InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, { Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, Supported: true, }, }, + InstallStrategy: newNginxInstallStrategy(depName, permissions, clusterPermissions), + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "v1alpha1", + Kind: crdPlural, + DisplayName: crdName, + Description: crdName, + }, + }, + }, }, } - Expect(ctx.Ctx().Client().Create(context.Background(), &original)).To(Succeed()) - - Eventually(func() error { - key := client.ObjectKeyFromObject(&original) - key.Namespace = target.GetName() - return ctx.Ctx().Client().Get(context.Background(), key, ©) - }).Should(Succeed()) - }) - AfterEach(func() { - if target.GetName() != "" { - Expect(ctx.Ctx().Client().Delete(context.Background(), &target)).To(Succeed()) - } - }) + // Create dependency first (CRD) + cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: crdName, + }, + Spec: apiextensions.CustomResourceDefinitionSpec{ + Group: "cluster.com", + Versions: []apiextensions.CustomResourceDefinitionVersion{ + { + Name: "v1alpha1", + Served: true, + Storage: true, + Schema: &apiextensions.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ + Type: "object", + Description: "my crd schema", + }, + }, + }, + }, + Names: apiextensions.CustomResourceDefinitionNames{ + Plural: crdPlural, + Singular: crdPlural, + Kind: crdPlural, + ListKind: "list" + crdPlural, + }, + Scope: apiextensions.NamespaceScoped, + }, + }) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCRD() - It("is synchronized with the original csv", func() { - Eventually(func() error { - key := client.ObjectKeyFromObject(©) + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), true, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - key.Namespace = target.Name - if err := ctx.Ctx().Client().Get(context.Background(), key, ©); err != nil { - return err - } + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvPendingChecker) + Expect(err).ShouldNot(HaveOccurred()) - copy.Status.LastUpdateTime = &metav1.Time{Time: time.Unix(1, 0)} - return ctx.Ctx().Client().Status().Update(context.Background(), ©) - }).Should(Succeed()) + // Shouldn't create deployment + Consistently(func() bool { + _, err := c.GetDeployment(ns.GetName(), depName) + return apierrors.IsNotFound(err) + }).Should(BeTrue()) + }) + It("create with unmet requirements API service", func() { - Eventually(func() (bool, error) { - key := client.ObjectKeyFromObject(&original) + depName := genName("dep-") + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), + }, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: newNginxInstallStrategy(depName, nil, nil), + APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ + Required: []operatorsv1alpha1.APIServiceDescription{ + { + DisplayName: "Not In Cluster", + Description: "An apiservice that is not currently in the cluster", + Group: "not.in.cluster.com", + Version: "v1alpha1", + Kind: "NotInCluster", + }, + }, + }, + }, + } - if err := ctx.Ctx().Client().Get(context.Background(), key, &original); err != nil { - return false, err - } + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - key.Namespace = target.Name - if err := ctx.Ctx().Client().Get(context.Background(), key, ©); err != nil { - return false, err - } + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvPendingChecker) + Expect(err).ShouldNot(HaveOccurred()) - return original.Status.LastUpdateTime.Equal(copy.Status.LastUpdateTime), nil - }).Should(BeTrue(), "Change to status of copy should have been reverted") + // Shouldn't create deployment + Consistently(func() bool { + _, err := c.GetDeployment(ns.GetName(), depName) + return apierrors.IsNotFound(err) + }).Should(BeTrue()) }) - }) + It("create with unmet permissions API service", func() { - When("a csv requires a serviceaccount solely owned by a non-csv", func() { - var ( - cm corev1.ConfigMap - sa corev1.ServiceAccount - csv operatorsv1alpha1.ClusterServiceVersion - ) - - BeforeEach(func() { - cm = corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "cm-", - Namespace: testNamespace, + saName := genName("dep-") + permissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ + { + ServiceAccountName: saName, + Rules: []rbacv1.PolicyRule{ + { + Verbs: []string{"create"}, + APIGroups: []string{""}, + Resources: []string{"deployment"}, + }, + }, }, } - Expect(ctx.Ctx().Client().Create(context.Background(), &cm)).To(Succeed()) - sa = corev1.ServiceAccount{ - ObjectMeta: metav1.ObjectMeta{ - GenerateName: "sa-", - Namespace: testNamespace, - OwnerReferences: []metav1.OwnerReference{ + clusterPermissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ + { + ServiceAccountName: saName, + Rules: []rbacv1.PolicyRule{ { - Name: cm.GetName(), - APIVersion: corev1.SchemeGroupVersion.String(), - Kind: "ConfigMap", - UID: cm.GetUID(), + Verbs: []string{"get"}, + APIGroups: []string{""}, + Resources: []string{"deployment"}, }, }, }, } - Expect(ctx.Ctx().Client().Create(context.Background(), &sa)).To(Succeed()) - csv = operatorsv1alpha1.ClusterServiceVersion{ + depName := genName("dep-") + csv := operatorsv1alpha1.ClusterServiceVersion{ TypeMeta: metav1.TypeMeta{ Kind: operatorsv1alpha1.ClusterServiceVersionKind, APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, }, ObjectMeta: metav1.ObjectMeta{ - GenerateName: "csv-", - Namespace: testNamespace, + Name: genName("csv"), }, Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: "foo", - Spec: appsv1.DeploymentSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"app": "foo"}, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{"app": "foo"}, - }, - Spec: corev1.PodSpec{Containers: []corev1.Container{ - { - Name: genName("foo"), - Image: *dummyImage, - }, - }}, - }, - }, - }, - }, - Permissions: []operatorsv1alpha1.StrategyDeploymentPermissions{ - { - ServiceAccountName: sa.GetName(), - Rules: []rbacv1.PolicyRule{}, - }, - }, - }, - }, + MinKubeVersion: "0.0.0", InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, { Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, Supported: true, }, }, + InstallStrategy: newNginxInstallStrategy(depName, permissions, clusterPermissions), + // Cheating a little; this is an APIservice that will exist for the e2e tests + APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ + Required: []operatorsv1alpha1.APIServiceDescription{ + { + Group: "packages.operators.coreos.com", + Version: "v1", + Kind: "PackageManifest", + DisplayName: "Package Manifest", + Description: "An apiservice that exists", + }, + }, + }, }, } - Expect(ctx.Ctx().Client().Create(context.Background(), &csv)).To(Succeed()) - }) - AfterEach(func() { - if cm.GetName() != "" { - Expect(ctx.Ctx().Client().Delete(context.Background(), &cm)).To(Succeed()) - } - }) + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - It("considers the serviceaccount requirement satisfied", func() { - Eventually(func() (operatorsv1alpha1.StatusReason, error) { - if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&csv), &csv); err != nil { - return "", err - } - for _, requirement := range csv.Status.RequirementStatus { - if requirement.Name != sa.GetName() { - continue - } - return requirement.Status, nil - } - return "", fmt.Errorf("missing expected requirement %q", sa.GetName()) - }).Should(Equal(operatorsv1alpha1.RequirementStatusReasonPresent)) - }) - }) + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvPendingChecker) + Expect(err).ShouldNot(HaveOccurred()) - It("create with unmet requirements min kube version", func() { + // Shouldn't create deployment + Consistently(func() bool { + _, err := c.GetDeployment(ns.GetName(), depName) + return apierrors.IsNotFound(err) + }).Should(BeTrue()) + }) + It("create with unmet requirements native API", func() { - depName := genName("dep-") - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "999.999.999", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, + depName := genName("dep-") + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, }, - InstallStrategy: newNginxInstallStrategy(depName, nil, nil), - }, - } - - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() - - _, err = fetchCSV(crc, csv.Name, testNamespace, csvPendingChecker) - Expect(err).ShouldNot(HaveOccurred()) - - // Shouldn't create deployment - Consistently(func() bool { - _, err := c.GetDeployment(testNamespace, depName) - return k8serrors.IsNotFound(err) - }).Should(BeTrue()) - }) - // TODO: same test but missing serviceaccount instead - It("create with unmet requirements CRD", func() { - - depName := genName("dep-") - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), }, - InstallStrategy: newNginxInstallStrategy(depName, nil, nil), - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, { - DisplayName: "Not In Cluster", - Description: "A CRD that is not currently in the cluster", - Name: "not.in.cluster.com", - Version: "v1alpha1", - Kind: "NotInCluster", + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, }, }, + InstallStrategy: newNginxInstallStrategy(depName, nil, nil), + NativeAPIs: []metav1.GroupVersionKind{{Group: "kubenative.io", Version: "v1", Kind: "Native"}}, }, - }, - } - - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() + } - _, err = fetchCSV(crc, csv.Name, testNamespace, csvPendingChecker) - Expect(err).ShouldNot(HaveOccurred()) + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - // Shouldn't create deployment - Consistently(func() bool { - _, err := c.GetDeployment(testNamespace, depName) - return k8serrors.IsNotFound(err) - }).Should(BeTrue()) - }) + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvPendingChecker) + Expect(err).ShouldNot(HaveOccurred()) - It("create with unmet permissions CRD", func() { + // Shouldn't create deployment + Consistently(func() bool { + _, err := c.GetDeployment(ns.GetName(), depName) + return apierrors.IsNotFound(err) + }).Should(BeTrue()) + }) + // TODO: same test but create serviceaccount instead + It("create requirements met CRD", func() { - saName := genName("dep-") - permissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ - { - ServiceAccountName: saName, - Rules: []rbacv1.PolicyRule{ - { - Verbs: []string{"create"}, - APIGroups: []string{""}, - Resources: []string{"deployment"}, + saName := genName("sa-") + permissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ + { + ServiceAccountName: saName, + Rules: []rbacv1.PolicyRule{ + { + Verbs: []string{"create"}, + APIGroups: []string{""}, + Resources: []string{"deployment"}, + }, }, }, - }, - } + } - clusterPermissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ - { - ServiceAccountName: saName, - Rules: []rbacv1.PolicyRule{ - { - Verbs: []string{"get"}, - APIGroups: []string{""}, - Resources: []string{"deployment"}, + clusterPermissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ + { + ServiceAccountName: saName, + Rules: []rbacv1.PolicyRule{ + { + Verbs: []string{"get"}, + APIGroups: []string{""}, + Resources: []string{"deployment"}, + }, + { + Verbs: []string{"put", "post", "get"}, + NonResourceURLs: []string{"/osb", "/osb/*"}, + }, }, }, - }, - } + } - crdPlural := genName("ins") - crdName := crdPlural + ".cluster.com" - depName := genName("dep-") - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, + crdPlural := genName("ins") + crdName := crdPlural + ".cluster.com" + depName := genName("dep-") + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), }, - InstallStrategy: newNginxInstallStrategy(depName, permissions, clusterPermissions), - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ { - Name: crdName, - Version: "v1alpha1", - Kind: crdPlural, - DisplayName: crdName, - Description: crdName, + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, }, - }, - }, - }, - } - - // Create dependency first (CRD) - cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{ - Name: crdName, - }, - Spec: apiextensions.CustomResourceDefinitionSpec{ - Group: "cluster.com", - Versions: []apiextensions.CustomResourceDefinitionVersion{ - { - Name: "v1alpha1", - Served: true, - Storage: true, - Schema: &apiextensions.CustomResourceValidation{ - OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ - Type: "object", - Description: "my crd schema", + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: newNginxInstallStrategy(depName, permissions, clusterPermissions), + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "v1alpha1", + Kind: crdPlural, + DisplayName: crdName, + Description: crdName, }, }, }, }, - Names: apiextensions.CustomResourceDefinitionNames{ - Plural: crdPlural, - Singular: crdPlural, - Kind: crdPlural, - ListKind: "list" + crdPlural, - }, - Scope: apiextensions.NamespaceScoped, - }, - }) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCRD() - - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, true, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() + } - _, err = fetchCSV(crc, csv.Name, testNamespace, csvPendingChecker) - Expect(err).ShouldNot(HaveOccurred()) + // Create CSV first, knowing it will fail + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), true, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - // Shouldn't create deployment - Consistently(func() bool { - _, err := c.GetDeployment(testNamespace, depName) - return k8serrors.IsNotFound(err) - }).Should(BeTrue()) - }) - It("create with unmet requirements API service", func() { + fetchedCSV, err := fetchCSV(crc, csv.Name, ns.GetName(), csvPendingChecker) + Expect(err).ShouldNot(HaveOccurred()) - depName := genName("dep-") - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, + sa := corev1.ServiceAccount{} + sa.SetName(saName) + sa.SetNamespace(ns.GetName()) + sa.SetOwnerReferences([]metav1.OwnerReference{{ + Name: fetchedCSV.GetName(), APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + UID: fetchedCSV.GetUID(), + }}) + _, err = c.CreateServiceAccount(&sa) + Expect(err).ShouldNot(HaveOccurred(), "could not create ServiceAccount %#v", sa) + + crd := apiextensions.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: crdName, }, - InstallStrategy: newNginxInstallStrategy(depName, nil, nil), - APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ - Required: []operatorsv1alpha1.APIServiceDescription{ + Spec: apiextensions.CustomResourceDefinitionSpec{ + Group: "cluster.com", + Versions: []apiextensions.CustomResourceDefinitionVersion{ { - DisplayName: "Not In Cluster", - Description: "An apiservice that is not currently in the cluster", - Group: "not.in.cluster.com", - Version: "v1alpha1", - Kind: "NotInCluster", + Name: "v1alpha1", + Served: true, + Storage: true, + Schema: &apiextensions.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ + Type: "object", + Description: "my crd schema", + }, + }, }, }, - }, - }, - } - - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() - - _, err = fetchCSV(crc, csv.Name, testNamespace, csvPendingChecker) - Expect(err).ShouldNot(HaveOccurred()) - - // Shouldn't create deployment - Consistently(func() bool { - _, err := c.GetDeployment(testNamespace, depName) - return k8serrors.IsNotFound(err) - }).Should(BeTrue()) - }) - It("create with unmet permissions API service", func() { - - saName := genName("dep-") - permissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ - { - ServiceAccountName: saName, - Rules: []rbacv1.PolicyRule{ - { - Verbs: []string{"create"}, - APIGroups: []string{""}, - Resources: []string{"deployment"}, + Names: apiextensions.CustomResourceDefinitionNames{ + Plural: crdPlural, + Singular: crdPlural, + Kind: crdPlural, + ListKind: "list" + crdPlural, }, + Scope: apiextensions.NamespaceScoped, }, - }, - } + } + crd.SetOwnerReferences([]metav1.OwnerReference{{ + Name: fetchedCSV.GetName(), + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + UID: fetchedCSV.GetUID(), + }}) + cleanupCRD, err := createCRD(c, crd) + defer cleanupCRD() + Expect(err).ShouldNot(HaveOccurred()) - clusterPermissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ - { - ServiceAccountName: saName, + // Create Role/Cluster Roles and RoleBindings + role := rbacv1.Role{ Rules: []rbacv1.PolicyRule{ { - Verbs: []string{"get"}, + Verbs: []string{"create"}, APIGroups: []string{""}, Resources: []string{"deployment"}, }, }, - }, - } + } + role.SetName(genName("dep-")) + role.SetNamespace(ns.GetName()) + _, err = c.CreateRole(&role) + Expect(err).ShouldNot(HaveOccurred(), "could not create Role") - depName := genName("dep-") - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, + roleBinding := rbacv1.RoleBinding{ + Subjects: []rbacv1.Subject{ { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, - }, - InstallStrategy: newNginxInstallStrategy(depName, permissions, clusterPermissions), - // Cheating a little; this is an APIservice that will exist for the e2e tests - APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ - Required: []operatorsv1alpha1.APIServiceDescription{ - { - Group: "packages.operators.coreos.com", - Version: "v1", - Kind: "PackageManifest", - DisplayName: "Package Manifest", - Description: "An apiservice that exists", - }, + Kind: "ServiceAccount", + APIGroup: "", + Name: sa.GetName(), + Namespace: sa.GetNamespace(), }, }, - }, - } - - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() - - _, err = fetchCSV(crc, csv.Name, testNamespace, csvPendingChecker) - Expect(err).ShouldNot(HaveOccurred()) - - // Shouldn't create deployment - Consistently(func() bool { - _, err := c.GetDeployment(testNamespace, depName) - return k8serrors.IsNotFound(err) - }).Should(BeTrue()) - }) - It("create with unmet requirements native API", func() { - - depName := genName("dep-") - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: role.GetName(), }, - InstallStrategy: newNginxInstallStrategy(depName, nil, nil), - NativeAPIs: []metav1.GroupVersionKind{{Group: "kubenative.io", Version: "v1", Kind: "Native"}}, - }, - } - - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() - - _, err = fetchCSV(crc, csv.Name, testNamespace, csvPendingChecker) - Expect(err).ShouldNot(HaveOccurred()) - - // Shouldn't create deployment - Consistently(func() bool { - _, err := c.GetDeployment(testNamespace, depName) - return k8serrors.IsNotFound(err) - }).Should(BeTrue()) - }) - // TODO: same test but create serviceaccount instead - It("create requirements met CRD", func() { + } + roleBinding.SetName(genName("dep-")) + roleBinding.SetNamespace(ns.GetName()) + _, err = c.CreateRoleBinding(&roleBinding) + Expect(err).ShouldNot(HaveOccurred(), "could not create RoleBinding") - saName := genName("sa-") - permissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ - { - ServiceAccountName: saName, + clusterRole := rbacv1.ClusterRole{ Rules: []rbacv1.PolicyRule{ { - Verbs: []string{"create"}, + Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"deployment"}, }, }, - }, - } + } + clusterRole.SetName(genName("dep-")) + _, err = c.CreateClusterRole(&clusterRole) + Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRole") - clusterPermissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ - { - ServiceAccountName: saName, + nonResourceClusterRole := rbacv1.ClusterRole{ Rules: []rbacv1.PolicyRule{ - { - Verbs: []string{"get"}, - APIGroups: []string{""}, - Resources: []string{"deployment"}, - }, { Verbs: []string{"put", "post", "get"}, NonResourceURLs: []string{"/osb", "/osb/*"}, }, }, - }, - } + } + nonResourceClusterRole.SetName(genName("dep-")) + _, err = c.CreateClusterRole(&nonResourceClusterRole) + Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRole") - crdPlural := genName("ins") - crdName := crdPlural + ".cluster.com" - depName := genName("dep-") - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, + clusterRoleBinding := rbacv1.ClusterRoleBinding{ + Subjects: []rbacv1.Subject{ { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + Kind: "ServiceAccount", + APIGroup: "", + Name: sa.GetName(), + Namespace: sa.GetNamespace(), }, }, - InstallStrategy: newNginxInstallStrategy(depName, permissions, clusterPermissions), - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ - { - Name: crdName, - Version: "v1alpha1", - Kind: crdPlural, - DisplayName: crdName, - Description: crdName, - }, - }, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: clusterRole.GetName(), }, - }, - } - - // Create CSV first, knowing it will fail - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, true, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() - - fetchedCSV, err := fetchCSV(crc, csv.Name, testNamespace, csvPendingChecker) - Expect(err).ShouldNot(HaveOccurred()) + } + clusterRoleBinding.SetName(genName("dep-")) + _, err = c.CreateClusterRoleBinding(&clusterRoleBinding) + Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRoleBinding") - sa := corev1.ServiceAccount{} - sa.SetName(saName) - sa.SetNamespace(testNamespace) - sa.SetOwnerReferences([]metav1.OwnerReference{{ - Name: fetchedCSV.GetName(), - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - UID: fetchedCSV.GetUID(), - }}) - _, err = c.CreateServiceAccount(&sa) - Expect(err).ShouldNot(HaveOccurred(), "could not create ServiceAccount %#v", sa) - - crd := apiextensions.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{ - Name: crdName, - }, - Spec: apiextensions.CustomResourceDefinitionSpec{ - Group: "cluster.com", - Versions: []apiextensions.CustomResourceDefinitionVersion{ + nonResourceClusterRoleBinding := rbacv1.ClusterRoleBinding{ + Subjects: []rbacv1.Subject{ { - Name: "v1alpha1", - Served: true, - Storage: true, - Schema: &apiextensions.CustomResourceValidation{ - OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ - Type: "object", - Description: "my crd schema", - }, - }, + Kind: "ServiceAccount", + APIGroup: "", + Name: sa.GetName(), + Namespace: sa.GetNamespace(), }, }, - Names: apiextensions.CustomResourceDefinitionNames{ - Plural: crdPlural, - Singular: crdPlural, - Kind: crdPlural, - ListKind: "list" + crdPlural, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: nonResourceClusterRole.GetName(), }, - Scope: apiextensions.NamespaceScoped, - }, - } - crd.SetOwnerReferences([]metav1.OwnerReference{{ - Name: fetchedCSV.GetName(), - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - UID: fetchedCSV.GetUID(), - }}) - cleanupCRD, err := createCRD(c, crd) - defer cleanupCRD() - Expect(err).ShouldNot(HaveOccurred()) + } + nonResourceClusterRoleBinding.SetName(genName("dep-")) + _, err = c.CreateClusterRoleBinding(&nonResourceClusterRoleBinding) + Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRoleBinding") - // Create Role/Cluster Roles and RoleBindings - role := rbacv1.Role{ - Rules: []rbacv1.PolicyRule{ - { - Verbs: []string{"create"}, - APIGroups: []string{""}, - Resources: []string{"deployment"}, - }, - }, - } - role.SetName(genName("dep-")) - role.SetNamespace(testNamespace) - _, err = c.CreateRole(&role) - Expect(err).ShouldNot(HaveOccurred(), "could not create Role") + ctx.Ctx().Logf("checking for deployment") + // Poll for deployment to be ready + Eventually(func() (bool, error) { + dep, err := c.GetDeployment(ns.GetName(), depName) + if apierrors.IsNotFound(err) { + ctx.Ctx().Logf("deployment %s not found\n", depName) + return false, nil + } else if err != nil { + ctx.Ctx().Logf("unexpected error fetching deployment %s\n", depName) + return false, err + } + if dep.Status.UpdatedReplicas == *(dep.Spec.Replicas) && + dep.Status.Replicas == *(dep.Spec.Replicas) && + dep.Status.AvailableReplicas == *(dep.Spec.Replicas) { + ctx.Ctx().Logf("deployment ready") + return true, nil + } + ctx.Ctx().Logf("deployment not ready") + return false, nil + }).Should(BeTrue()) - roleBinding := rbacv1.RoleBinding{ - Subjects: []rbacv1.Subject{ - { - Kind: "ServiceAccount", - APIGroup: "", - Name: sa.GetName(), - Namespace: sa.GetNamespace(), - }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "Role", - Name: role.GetName(), - }, - } - roleBinding.SetName(genName("dep-")) - roleBinding.SetNamespace(testNamespace) - _, err = c.CreateRoleBinding(&roleBinding) - Expect(err).ShouldNot(HaveOccurred(), "could not create RoleBinding") + fetchedCSV, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - clusterRole := rbacv1.ClusterRole{ - Rules: []rbacv1.PolicyRule{ - { - Verbs: []string{"get"}, - APIGroups: []string{""}, - Resources: []string{"deployment"}, - }, - }, - } - clusterRole.SetName(genName("dep-")) - _, err = c.CreateClusterRole(&clusterRole) - Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRole") + // Delete CRD + cleanupCRD() - nonResourceClusterRole := rbacv1.ClusterRole{ - Rules: []rbacv1.PolicyRule{ - { - Verbs: []string{"put", "post", "get"}, - NonResourceURLs: []string{"/osb", "/osb/*"}, - }, - }, - } - nonResourceClusterRole.SetName(genName("dep-")) - _, err = c.CreateClusterRole(&nonResourceClusterRole) - Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRole") + // Wait for CSV failure + fetchedCSV, err = fetchCSV(crc, csv.Name, ns.GetName(), csvPendingChecker) + Expect(err).ShouldNot(HaveOccurred()) + + // Recreate the CRD + cleanupCRD, err = createCRD(c, crd) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCRD() + + // Wait for CSV success again + fetchedCSV, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) + }) + It("create requirements met API service", func() { + + sa := corev1.ServiceAccount{} + sa.SetName(genName("sa-")) + sa.SetNamespace(ns.GetName()) + _, err := c.CreateServiceAccount(&sa) + Expect(err).ShouldNot(HaveOccurred(), "could not create ServiceAccount") - clusterRoleBinding := rbacv1.ClusterRoleBinding{ - Subjects: []rbacv1.Subject{ + permissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ { - Kind: "ServiceAccount", - APIGroup: "", - Name: sa.GetName(), - Namespace: sa.GetNamespace(), + ServiceAccountName: sa.GetName(), + Rules: []rbacv1.PolicyRule{ + { + Verbs: []string{"create"}, + APIGroups: []string{""}, + Resources: []string{"deployment"}, + }, + }, }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: clusterRole.GetName(), - }, - } - clusterRoleBinding.SetName(genName("dep-")) - _, err = c.CreateClusterRoleBinding(&clusterRoleBinding) - Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRoleBinding") + } - nonResourceClusterRoleBinding := rbacv1.ClusterRoleBinding{ - Subjects: []rbacv1.Subject{ + clusterPermissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ { - Kind: "ServiceAccount", - APIGroup: "", - Name: sa.GetName(), - Namespace: sa.GetNamespace(), + ServiceAccountName: sa.GetName(), + Rules: []rbacv1.PolicyRule{ + { + Verbs: []string{"get"}, + APIGroups: []string{""}, + Resources: []string{"deployment"}, + }, + }, }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: nonResourceClusterRole.GetName(), - }, - } - nonResourceClusterRoleBinding.SetName(genName("dep-")) - _, err = c.CreateClusterRoleBinding(&nonResourceClusterRoleBinding) - Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRoleBinding") - - ctx.Ctx().Logf("checking for deployment") - // Poll for deployment to be ready - Eventually(func() (bool, error) { - dep, err := c.GetDeployment(testNamespace, depName) - if k8serrors.IsNotFound(err) { - ctx.Ctx().Logf("deployment %s not found\n", depName) - return false, nil - } else if err != nil { - ctx.Ctx().Logf("unexpected error fetching deployment %s\n", depName) - return false, err } - if dep.Status.UpdatedReplicas == *(dep.Spec.Replicas) && - dep.Status.Replicas == *(dep.Spec.Replicas) && - dep.Status.AvailableReplicas == *(dep.Spec.Replicas) { - ctx.Ctx().Logf("deployment ready") - return true, nil - } - ctx.Ctx().Logf("deployment not ready") - return false, nil - }).Should(BeTrue()) - - fetchedCSV, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) - - // Delete CRD - cleanupCRD() - - // Wait for CSV failure - fetchedCSV, err = fetchCSV(crc, csv.Name, testNamespace, csvPendingChecker) - Expect(err).ShouldNot(HaveOccurred()) - - // Recreate the CRD - cleanupCRD, err = createCRD(c, crd) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCRD() - - // Wait for CSV success again - fetchedCSV, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) - }) - It("create requirements met API service", func() { - - sa := corev1.ServiceAccount{} - sa.SetName(genName("sa-")) - sa.SetNamespace(testNamespace) - _, err := c.CreateServiceAccount(&sa) - Expect(err).ShouldNot(HaveOccurred(), "could not create ServiceAccount") - permissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ - { - ServiceAccountName: sa.GetName(), - Rules: []rbacv1.PolicyRule{ - { - Verbs: []string{"create"}, - APIGroups: []string{""}, - Resources: []string{"deployment"}, + depName := genName("dep-") + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), + }, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: newNginxInstallStrategy(depName, permissions, clusterPermissions), + // Cheating a little; this is an APIservice that will exist for the e2e tests + APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ + Required: []operatorsv1alpha1.APIServiceDescription{ + { + Group: "packages.operators.coreos.com", + Version: "v1", + Kind: "PackageManifest", + DisplayName: "Package Manifest", + Description: "An apiservice that exists", + }, + }, }, }, - }, - } + } - clusterPermissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ - { - ServiceAccountName: sa.GetName(), + // Create Role/Cluster Roles and RoleBindings + role := rbacv1.Role{ Rules: []rbacv1.PolicyRule{ { - Verbs: []string{"get"}, + Verbs: []string{"create"}, APIGroups: []string{""}, Resources: []string{"deployment"}, }, }, - }, - } + } + role.SetName(genName("dep-")) + role.SetNamespace(ns.GetName()) + _, err = c.CreateRole(&role) + Expect(err).ShouldNot(HaveOccurred(), "could not create Role") - depName := genName("dep-") - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, + roleBinding := rbacv1.RoleBinding{ + Subjects: []rbacv1.Subject{ { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, - }, - InstallStrategy: newNginxInstallStrategy(depName, permissions, clusterPermissions), - // Cheating a little; this is an APIservice that will exist for the e2e tests - APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ - Required: []operatorsv1alpha1.APIServiceDescription{ - { - Group: "packages.operators.coreos.com", - Version: "v1", - Kind: "PackageManifest", - DisplayName: "Package Manifest", - Description: "An apiservice that exists", - }, + Kind: "ServiceAccount", + APIGroup: "", + Name: sa.GetName(), + Namespace: sa.GetNamespace(), }, }, - }, - } - - // Create Role/Cluster Roles and RoleBindings - role := rbacv1.Role{ - Rules: []rbacv1.PolicyRule{ - { - Verbs: []string{"create"}, - APIGroups: []string{""}, - Resources: []string{"deployment"}, + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "Role", + Name: role.GetName(), }, - }, - } - role.SetName(genName("dep-")) - role.SetNamespace(testNamespace) - _, err = c.CreateRole(&role) - Expect(err).ShouldNot(HaveOccurred(), "could not create Role") + } + roleBinding.SetName(genName("dep-")) + roleBinding.SetNamespace(ns.GetName()) + _, err = c.CreateRoleBinding(&roleBinding) + Expect(err).ShouldNot(HaveOccurred(), "could not create RoleBinding") - roleBinding := rbacv1.RoleBinding{ - Subjects: []rbacv1.Subject{ - { - Kind: "ServiceAccount", - APIGroup: "", - Name: sa.GetName(), - Namespace: sa.GetNamespace(), + clusterRole := rbacv1.ClusterRole{ + Rules: []rbacv1.PolicyRule{ + { + Verbs: []string{"get"}, + APIGroups: []string{""}, + Resources: []string{"deployment"}, + }, }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "Role", - Name: role.GetName(), - }, - } - roleBinding.SetName(genName("dep-")) - roleBinding.SetNamespace(testNamespace) - _, err = c.CreateRoleBinding(&roleBinding) - Expect(err).ShouldNot(HaveOccurred(), "could not create RoleBinding") + } + clusterRole.SetName(genName("dep-")) + _, err = c.CreateClusterRole(&clusterRole) + Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRole") - clusterRole := rbacv1.ClusterRole{ - Rules: []rbacv1.PolicyRule{ - { - Verbs: []string{"get"}, - APIGroups: []string{""}, - Resources: []string{"deployment"}, + clusterRoleBinding := rbacv1.ClusterRoleBinding{ + Subjects: []rbacv1.Subject{ + { + Kind: "ServiceAccount", + APIGroup: "", + Name: sa.GetName(), + Namespace: sa.GetNamespace(), + }, }, - }, - } - clusterRole.SetName(genName("dep-")) - _, err = c.CreateClusterRole(&clusterRole) - Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRole") - - clusterRoleBinding := rbacv1.ClusterRoleBinding{ - Subjects: []rbacv1.Subject{ - { - Kind: "ServiceAccount", - APIGroup: "", - Name: sa.GetName(), - Namespace: sa.GetNamespace(), + RoleRef: rbacv1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: clusterRole.GetName(), }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: clusterRole.GetName(), - }, - } - clusterRoleBinding.SetName(genName("dep-")) - _, err = c.CreateClusterRoleBinding(&clusterRoleBinding) - Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRoleBinding") + } + clusterRoleBinding.SetName(genName("dep-")) + _, err = c.CreateClusterRoleBinding(&clusterRoleBinding) + Expect(err).ShouldNot(HaveOccurred(), "could not create ClusterRoleBinding") - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - fetchedCSV, err := fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + fetchedCSV, err := fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - // Fetch cluster service version again to check for unnecessary control loops - sameCSV, err := fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) - Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV)) - }) - It("create with owned API service", func() { - - depName := genName("hat-server") - mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName("")) - version := "v1alpha1" - mockGroupVersion := strings.Join([]string{mockGroup, version}, "/") - mockKinds := []string{"fez", "fedora"} - depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}}) - apiServiceName := strings.Join([]string{version, mockGroup}, ".") - - // Create CSV for the package-server - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: depName, - Spec: depSpec, - }, - }, - } + // Fetch cluster service version again to check for unnecessary control loops + sameCSV, err := fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) + Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV)) + }) + It("create with owned API service", func() { - owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds)) - for i, kind := range mockKinds { - owned[i] = operatorsv1alpha1.APIServiceDescription{ - Name: apiServiceName, - Group: mockGroup, - Version: version, - Kind: kind, - DeploymentName: depName, - ContainerPort: int32(5443), - DisplayName: kind, - Description: fmt.Sprintf("A %s", kind), - } - } + depName := genName("hat-server") + mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName("")) + version := "v1alpha1" + mockGroupVersion := strings.Join([]string{mockGroup, version}, "/") + mockKinds := []string{"fez", "fedora"} + depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}}) + apiServiceName := strings.Join([]string{version, mockGroup}, ".") - csv := operatorsv1alpha1.ClusterServiceVersion{ - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ + // Create CSV for the package-server + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, + Name: depName, + Spec: depSpec, }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, + }, + } + + owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds)) + for i, kind := range mockKinds { + owned[i] = operatorsv1alpha1.APIServiceDescription{ + Name: apiServiceName, + Group: mockGroup, + Version: version, + Kind: kind, + DeploymentName: depName, + ContainerPort: int32(5443), + DisplayName: kind, + Description: fmt.Sprintf("A %s", kind), + } + } + + csv := operatorsv1alpha1.ClusterServiceVersion{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ + Owned: owned, }, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, - }, - APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ - Owned: owned, - }, - }, - } - csv.SetName(depName) + } + csv.SetName(depName) - // Create the APIService CSV - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) - defer func() { - watcher, err := c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Watch(context.TODO(), metav1.ListOptions{FieldSelector: "metadata.name=" + apiServiceName}) + // Create the APIService CSV + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, false) Expect(err).ShouldNot(HaveOccurred()) - - deleted := make(chan struct{}) - go func() { - defer GinkgoRecover() - events := watcher.ResultChan() - for { - select { - case evt := <-events: - if evt.Type == watch.Deleted { - deleted <- struct{}{} - return + defer func() { + watcher, err := c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Watch(context.TODO(), metav1.ListOptions{FieldSelector: "metadata.name=" + apiServiceName}) + Expect(err).ShouldNot(HaveOccurred()) + + deleted := make(chan struct{}) + go func() { + defer GinkgoRecover() + events := watcher.ResultChan() + for { + select { + case evt := <-events: + if evt.Type == watch.Deleted { + deleted <- struct{}{} + return + } + case <-time.After(pollDuration): + Fail("API service not cleaned up after CSV deleted") } - case <-time.After(pollDuration): - Fail("API service not cleaned up after CSV deleted") } - } + }() + + cleanupCSV() + <-deleted }() - cleanupCSV() - <-deleted - }() + fetchedCSV, err := fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - fetchedCSV, err := fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + // Should create Deployment + dep, err := c.GetDeployment(ns.GetName(), depName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected Deployment") - // Should create Deployment - dep, err := c.GetDeployment(testNamespace, depName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected Deployment") - - // Should create APIService - apiService, err := c.GetAPIService(apiServiceName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService") - - // Should create Service - serviceName := fmt.Sprintf("%s-service", depName) - _, err = c.GetService(testNamespace, serviceName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected Service") - - // Should create certificate Secret - secretName := fmt.Sprintf("%s-cert", serviceName) - _, err = c.GetSecret(testNamespace, secretName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret") - - // Should create a Role for the Secret - _, err = c.GetRole(testNamespace, secretName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret Role") - - // Should create a RoleBinding for the Secret - _, err = c.GetRoleBinding(testNamespace, secretName) - Expect(err).ShouldNot(HaveOccurred(), "error getting exptected Secret RoleBinding") - - // Should create a system:auth-delegator Cluster RoleBinding - _, err = c.GetClusterRoleBinding(fmt.Sprintf("%s-system:auth-delegator", serviceName)) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected system:auth-delegator ClusterRoleBinding") - - // Should create an extension-apiserver-authentication-reader RoleBinding in kube-system - _, err = c.GetRoleBinding("kube-system", fmt.Sprintf("%s-auth-reader", serviceName)) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected extension-apiserver-authentication-reader RoleBinding") - - // Store the ca sha annotation - oldCAAnnotation, ok := dep.Spec.Template.GetAnnotations()[install.OLMCAHashAnnotationKey] - Expect(ok).Should(BeTrue(), "expected olm sha annotation not present on existing pod template") - - // Induce a cert rotation - Eventually(Apply(fetchedCSV, func(csv *operatorsv1alpha1.ClusterServiceVersion) error { - now := metav1.Now() - csv.Status.CertsLastUpdated = &now - csv.Status.CertsRotateAt = &now - return nil - })).Should(Succeed()) - - _, err = fetchCSV(crc, csv.Name, testNamespace, func(csv *operatorsv1alpha1.ClusterServiceVersion) bool { - // Should create deployment - dep, err = c.GetDeployment(testNamespace, depName) - if err != nil { - return false - } + // Should create APIService + apiService, err := c.GetAPIService(apiServiceName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService") - // Should have a new ca hash annotation - newCAAnnotation, ok := dep.Spec.Template.GetAnnotations()[install.OLMCAHashAnnotationKey] - if !ok { - ctx.Ctx().Logf("expected olm sha annotation not present in new pod template") - return false - } + // Should create Service + serviceName := fmt.Sprintf("%s-service", depName) + _, err = c.GetService(ns.GetName(), serviceName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected Service") - if newCAAnnotation != oldCAAnnotation { - // Check for success - return csvSucceededChecker(csv) - } + // Should create certificate Secret + secretName := fmt.Sprintf("%s-cert", serviceName) + _, err = c.GetSecret(ns.GetName(), secretName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret") - return false - }) - Expect(err).ShouldNot(HaveOccurred(), "failed to rotate cert") + // Should create a Role for the Secret + _, err = c.GetRole(ns.GetName(), secretName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret Role") - // Get the APIService UID - oldAPIServiceUID := apiService.GetUID() + // Should create a RoleBinding for the Secret + _, err = c.GetRoleBinding(ns.GetName(), secretName) + Expect(err).ShouldNot(HaveOccurred(), "error getting exptected Secret RoleBinding") - // Delete the APIService - err = c.DeleteAPIService(apiServiceName, &metav1.DeleteOptions{}) - Expect(err).ShouldNot(HaveOccurred()) + // Should create a system:auth-delegator Cluster RoleBinding + _, err = c.GetClusterRoleBinding(fmt.Sprintf("%s-system:auth-delegator", serviceName)) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected system:auth-delegator ClusterRoleBinding") + + // Should create an extension-apiserver-authentication-reader RoleBinding in kube-system + _, err = c.GetRoleBinding("kube-system", fmt.Sprintf("%s-auth-reader", serviceName)) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected extension-apiserver-authentication-reader RoleBinding") + + // Store the ca sha annotation + oldCAAnnotation, ok := dep.Spec.Template.GetAnnotations()[install.OLMCAHashAnnotationKey] + Expect(ok).Should(BeTrue(), "expected olm sha annotation not present on existing pod template") + + // Induce a cert rotation + Eventually(Apply(fetchedCSV, func(csv *operatorsv1alpha1.ClusterServiceVersion) error { + now := metav1.Now() + csv.Status.CertsLastUpdated = &now + csv.Status.CertsRotateAt = &now + return nil + })).Should(Succeed()) + + _, err = fetchCSV(crc, csv.Name, ns.GetName(), func(csv *operatorsv1alpha1.ClusterServiceVersion) bool { + // Should create deployment + dep, err = c.GetDeployment(ns.GetName(), depName) + if err != nil { + return false + } + + // Should have a new ca hash annotation + newCAAnnotation, ok := dep.Spec.Template.GetAnnotations()[install.OLMCAHashAnnotationKey] + if !ok { + ctx.Ctx().Logf("expected olm sha annotation not present in new pod template") + return false + } + + if newCAAnnotation != oldCAAnnotation { + // Check for success + return csvSucceededChecker(csv) + } - // Wait for CSV success - fetchedCSV, err = fetchCSV(crc, csv.GetName(), testNamespace, func(csv *operatorsv1alpha1.ClusterServiceVersion) bool { - // Should create an APIService - apiService, err := c.GetAPIService(apiServiceName) - if err != nil { return false - } + }) + Expect(err).ShouldNot(HaveOccurred(), "failed to rotate cert") - if csvSucceededChecker(csv) { - return apiService.GetUID() != oldAPIServiceUID - } - return false + // Get the APIService UID + oldAPIServiceUID := apiService.GetUID() + + // Delete the APIService + err = c.DeleteAPIService(apiServiceName, &metav1.DeleteOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + + // Wait for CSV success + fetchedCSV, err = fetchCSV(crc, csv.GetName(), ns.GetName(), func(csv *operatorsv1alpha1.ClusterServiceVersion) bool { + // Should create an APIService + apiService, err := c.GetAPIService(apiServiceName) + if err != nil { + return false + } + + if csvSucceededChecker(csv) { + return apiService.GetUID() != oldAPIServiceUID + } + return false + }) + Expect(err).ShouldNot(HaveOccurred()) }) - Expect(err).ShouldNot(HaveOccurred()) - }) - It("update with owned API service", func() { - - depName := genName("hat-server") - mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName("")) - version := "v1alpha1" - mockGroupVersion := strings.Join([]string{mockGroup, version}, "/") - mockKinds := []string{"fedora"} - depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}}) - apiServiceName := strings.Join([]string{version, mockGroup}, ".") - - // Create CSVs for the hat-server - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: depName, - Spec: depSpec, - }, - }, - } + It("update with owned API service", func() { - owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds)) - for i, kind := range mockKinds { - owned[i] = operatorsv1alpha1.APIServiceDescription{ - Name: apiServiceName, - Group: mockGroup, - Version: version, - Kind: kind, - DeploymentName: depName, - ContainerPort: int32(5443), - DisplayName: kind, - Description: fmt.Sprintf("A %s", kind), - } - } + depName := genName("hat-server") + mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName("")) + version := "v1alpha1" + mockGroupVersion := strings.Join([]string{mockGroup, version}, "/") + mockKinds := []string{"fedora"} + depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}}) + apiServiceName := strings.Join([]string{version, mockGroup}, ".") - csv := operatorsv1alpha1.ClusterServiceVersion{ - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, + // Create CSVs for the hat-server + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + Name: depName, + Spec: depSpec, }, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, - }, - APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ - Owned: owned, - }, - }, - } - csv.SetName("csv-hat-1") - - // Create the APIService CSV - _, err := createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) + } - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds)) + for i, kind := range mockKinds { + owned[i] = operatorsv1alpha1.APIServiceDescription{ + Name: apiServiceName, + Group: mockGroup, + Version: version, + Kind: kind, + DeploymentName: depName, + ContainerPort: int32(5443), + DisplayName: kind, + Description: fmt.Sprintf("A %s", kind), + } + } - // Should create Deployment - _, err = c.GetDeployment(testNamespace, depName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected Deployment") - - // Should create APIService - _, err = c.GetAPIService(apiServiceName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService") - - // Should create Service - serviceName := fmt.Sprintf("%s-service", depName) - _, err = c.GetService(testNamespace, serviceName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected Service") - - // Should create certificate Secret - secretName := fmt.Sprintf("%s-cert", serviceName) - _, err = c.GetSecret(testNamespace, secretName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret") - - // Should create a Role for the Secret - _, err = c.GetRole(testNamespace, secretName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret Role") - - // Should create a RoleBinding for the Secret - _, err = c.GetRoleBinding(testNamespace, secretName) - Expect(err).ShouldNot(HaveOccurred(), "error getting exptected Secret RoleBinding") - - // Should create a system:auth-delegator Cluster RoleBinding - _, err = c.GetClusterRoleBinding(fmt.Sprintf("%s-system:auth-delegator", serviceName)) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected system:auth-delegator ClusterRoleBinding") - - // Should create an extension-apiserver-authentication-reader RoleBinding in kube-system - _, err = c.GetRoleBinding("kube-system", fmt.Sprintf("%s-auth-reader", serviceName)) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected extension-apiserver-authentication-reader RoleBinding") - - // Create a new CSV that owns the same API Service and replace the old CSV - csv2 := operatorsv1alpha1.ClusterServiceVersion{ - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - Replaces: csv.Name, - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, + csv := operatorsv1alpha1.ClusterServiceVersion{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ + Owned: owned, }, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, - }, - APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ - Owned: owned, - }, - }, - } - csv2.SetName("csv-hat-2") + } + csv.SetName("csv-hat-1") - // Create CSV2 to replace CSV - cleanupCSV2, err := createCSV(c, crc, csv2, testNamespace, false, true) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV2() + // Create the APIService CSV + _, err := createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) - _, err = fetchCSV(crc, csv2.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - // Should create Deployment - _, err = c.GetDeployment(testNamespace, depName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected Deployment") + // Should create Deployment + _, err = c.GetDeployment(ns.GetName(), depName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected Deployment") - // Should create APIService - _, err = c.GetAPIService(apiServiceName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService") + // Should create APIService + _, err = c.GetAPIService(apiServiceName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService") - // Should create Service - Eventually(func() error { - _, err := c.GetService(testNamespace, serviceName) - return err - }, timeout, interval).ShouldNot(HaveOccurred()) + // Should create Service + serviceName := fmt.Sprintf("%s-service", depName) + _, err = c.GetService(ns.GetName(), serviceName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected Service") - // Should create certificate Secret - secretName = fmt.Sprintf("%s-cert", serviceName) - Eventually(func() error { - _, err = c.GetSecret(testNamespace, secretName) - return err - }, timeout, interval).ShouldNot(HaveOccurred()) + // Should create certificate Secret + secretName := fmt.Sprintf("%s-cert", serviceName) + _, err = c.GetSecret(ns.GetName(), secretName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret") - // Should create a Role for the Secret - _, err = c.GetRole(testNamespace, secretName) - Eventually(func() error { - _, err = c.GetRole(testNamespace, secretName) - return err - }, timeout, interval).ShouldNot(HaveOccurred()) + // Should create a Role for the Secret + _, err = c.GetRole(ns.GetName(), secretName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret Role") - // Should create a RoleBinding for the Secret - Eventually(func() error { - _, err = c.GetRoleBinding(testNamespace, secretName) - return err - }, timeout, interval).ShouldNot(HaveOccurred()) + // Should create a RoleBinding for the Secret + _, err = c.GetRoleBinding(ns.GetName(), secretName) + Expect(err).ShouldNot(HaveOccurred(), "error getting exptected Secret RoleBinding") - // Should create a system:auth-delegator Cluster RoleBinding - Eventually(func() error { + // Should create a system:auth-delegator Cluster RoleBinding _, err = c.GetClusterRoleBinding(fmt.Sprintf("%s-system:auth-delegator", serviceName)) - return err - }, timeout, interval).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected system:auth-delegator ClusterRoleBinding") - // Should create an extension-apiserver-authentication-reader RoleBinding in kube-system - Eventually(func() error { + // Should create an extension-apiserver-authentication-reader RoleBinding in kube-system _, err = c.GetRoleBinding("kube-system", fmt.Sprintf("%s-auth-reader", serviceName)) - return err - }, timeout, interval).ShouldNot(HaveOccurred()) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected extension-apiserver-authentication-reader RoleBinding") + Expect(err).ShouldNot(HaveOccurred(), "error getting expected extension-apiserver-authentication-reader RoleBinding") - // Should eventually GC the CSV - Eventually(func() bool { - return csvExists(crc, csv.Name) - }).Should(BeFalse()) + // Create a new CSV that owns the same API Service and replace the old CSV + csv2 := operatorsv1alpha1.ClusterServiceVersion{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + Replaces: csv.Name, + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, + }, + APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ + Owned: owned, + }, + }, + } + csv2.SetName("csv-hat-2") - // Rename the initial CSV - csv.SetName("csv-hat-3") + // Create CSV2 to replace CSV + cleanupCSV2, err := createCSV(c, crc, csv2, ns.GetName(), false, true) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV2() - // Recreate the old CSV - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, true) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() + _, err = fetchCSV(crc, csv2.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - fetched, err := fetchCSV(crc, csv.Name, testNamespace, buildCSVReasonChecker(operatorsv1alpha1.CSVReasonOwnerConflict)) - Expect(err).ShouldNot(HaveOccurred()) - Expect(fetched.Status.Phase).Should(Equal(operatorsv1alpha1.CSVPhaseFailed)) - }) - It("create same CSV with owned API service multi namespace", func() { + // Should create Deployment + _, err = c.GetDeployment(ns.GetName(), depName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected Deployment") - // Create new namespace in a new operator group - secondNamespaceName := genName(testNamespace + "-") - matchingLabel := map[string]string{"inGroup": secondNamespaceName} + // Should create APIService + _, err = c.GetAPIService(apiServiceName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService") - _, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: secondNamespaceName, - Labels: matchingLabel, - }, - }, metav1.CreateOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - defer func() { - err = c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), secondNamespaceName, metav1.DeleteOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - }() + // Should create Service + Eventually(func() error { + _, err := c.GetService(ns.GetName(), serviceName) + return err + }, timeout, interval).ShouldNot(HaveOccurred()) - // Create a new operator group for the new namespace - operatorGroup := operatorsv1.OperatorGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: genName("e2e-operator-group-"), - Namespace: secondNamespaceName, - }, - Spec: operatorsv1.OperatorGroupSpec{ - Selector: &metav1.LabelSelector{ - MatchLabels: matchingLabel, - }, - }, - } - _, err = crc.OperatorsV1().OperatorGroups(secondNamespaceName).Create(context.TODO(), &operatorGroup, metav1.CreateOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - defer func() { - err = crc.OperatorsV1().OperatorGroups(secondNamespaceName).Delete(context.TODO(), operatorGroup.Name, metav1.DeleteOptions{}) + // Should create certificate Secret + secretName = fmt.Sprintf("%s-cert", serviceName) + Eventually(func() error { + _, err = c.GetSecret(ns.GetName(), secretName) + return err + }, timeout, interval).ShouldNot(HaveOccurred()) + + // Should create a Role for the Secret + _, err = c.GetRole(ns.GetName(), secretName) + Eventually(func() error { + _, err = c.GetRole(ns.GetName(), secretName) + return err + }, timeout, interval).ShouldNot(HaveOccurred()) + + // Should create a RoleBinding for the Secret + Eventually(func() error { + _, err = c.GetRoleBinding(ns.GetName(), secretName) + return err + }, timeout, interval).ShouldNot(HaveOccurred()) + + // Should create a system:auth-delegator Cluster RoleBinding + Eventually(func() error { + _, err = c.GetClusterRoleBinding(fmt.Sprintf("%s-system:auth-delegator", serviceName)) + return err + }, timeout, interval).ShouldNot(HaveOccurred()) + + // Should create an extension-apiserver-authentication-reader RoleBinding in kube-system + Eventually(func() error { + _, err = c.GetRoleBinding("kube-system", fmt.Sprintf("%s-auth-reader", serviceName)) + return err + }, timeout, interval).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected extension-apiserver-authentication-reader RoleBinding") + + // Should eventually GC the CSV + Eventually(func() bool { + return csvExists(ns.GetName(), crc, csv.Name) + }).Should(BeFalse()) + + // Rename the initial CSV + csv.SetName("csv-hat-3") + + // Recreate the old CSV + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, true) Expect(err).ShouldNot(HaveOccurred()) - }() + defer cleanupCSV() - ctx.Ctx().Logf("Waiting on new operator group to have correct status") - Eventually(func() ([]string, error) { - og, err := crc.OperatorsV1().OperatorGroups(secondNamespaceName).Get(context.TODO(), operatorGroup.Name, metav1.GetOptions{}) - if err != nil { - return nil, err - } - return og.Status.Namespaces, nil - }).Should(ConsistOf([]string{secondNamespaceName})) - - depName := genName("hat-server") - mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName("")) - version := "v1alpha1" - mockGroupVersion := strings.Join([]string{mockGroup, version}, "/") - mockKinds := []string{"fedora"} - depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}}) - apiServiceName := strings.Join([]string{version, mockGroup}, ".") - - // Create CSVs for the hat-server - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: depName, - Spec: depSpec, - }, - }, - } + fetched, err := fetchCSV(crc, csv.Name, ns.GetName(), buildCSVReasonChecker(operatorsv1alpha1.CSVReasonOwnerConflict)) + Expect(err).ShouldNot(HaveOccurred()) + Expect(fetched.Status.Phase).Should(Equal(operatorsv1alpha1.CSVPhaseFailed)) + }) + It("create same CSV with owned API service multi namespace", func() { - owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds)) - for i, kind := range mockKinds { - owned[i] = operatorsv1alpha1.APIServiceDescription{ - Name: apiServiceName, - Group: mockGroup, - Version: version, - Kind: kind, - DeploymentName: depName, - ContainerPort: int32(5443), - DisplayName: kind, - Description: fmt.Sprintf("A %s", kind), - } - } + // Create new namespace in a new operator group + secondNamespaceName := genName(ns.GetName() + "-") + matchingLabel := map[string]string{"inGroup": secondNamespaceName} - csv := operatorsv1alpha1.ClusterServiceVersion{ - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, + _, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: secondNamespaceName, + Labels: matchingLabel, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, + }, metav1.CreateOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + defer func() { + err = c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), secondNamespaceName, metav1.DeleteOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + }() + + // Create a new operator group for the new namespace + operatorGroup := operatorsv1.OperatorGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: genName("e2e-operator-group-"), + Namespace: secondNamespaceName, }, - APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ - Owned: owned, + Spec: operatorsv1.OperatorGroupSpec{ + Selector: &metav1.LabelSelector{ + MatchLabels: matchingLabel, + }, }, - }, - } - csv.SetName("csv-hat-1") + } + _, err = crc.OperatorsV1().OperatorGroups(secondNamespaceName).Create(context.TODO(), &operatorGroup, metav1.CreateOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + defer func() { + err = crc.OperatorsV1().OperatorGroups(secondNamespaceName).Delete(context.TODO(), operatorGroup.Name, metav1.DeleteOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + }() - // Create the initial CSV - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() + ctx.Ctx().Logf("Waiting on new operator group to have correct status") + Eventually(func() ([]string, error) { + og, err := crc.OperatorsV1().OperatorGroups(secondNamespaceName).Get(context.TODO(), operatorGroup.Name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + return og.Status.Namespaces, nil + }).Should(ConsistOf([]string{secondNamespaceName})) - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + depName := genName("hat-server") + mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName("")) + version := "v1alpha1" + mockGroupVersion := strings.Join([]string{mockGroup, version}, "/") + mockKinds := []string{"fedora"} + depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}}) + apiServiceName := strings.Join([]string{version, mockGroup}, ".") - // Should create Deployment - _, err = c.GetDeployment(testNamespace, depName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected Deployment") - - // Should create APIService - _, err = c.GetAPIService(apiServiceName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService") - - // Should create Service - serviceName := fmt.Sprintf("%s-service", depName) - _, err = c.GetService(testNamespace, serviceName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected Service") - - // Should create certificate Secret - secretName := fmt.Sprintf("%s-cert", serviceName) - _, err = c.GetSecret(testNamespace, secretName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret") - - // Should create a Role for the Secret - _, err = c.GetRole(testNamespace, secretName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret Role") - - // Should create a RoleBinding for the Secret - _, err = c.GetRoleBinding(testNamespace, secretName) - Expect(err).ShouldNot(HaveOccurred(), "error getting exptected Secret RoleBinding") - - // Should create a system:auth-delegator Cluster RoleBinding - _, err = c.GetClusterRoleBinding(fmt.Sprintf("%s-system:auth-delegator", serviceName)) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected system:auth-delegator ClusterRoleBinding") - - // Should create an extension-apiserver-authentication-reader RoleBinding in kube-system - _, err = c.GetRoleBinding("kube-system", fmt.Sprintf("%s-auth-reader", serviceName)) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected extension-apiserver-authentication-reader RoleBinding") - - // Create a new CSV that owns the same API Service but in a different namespace - csv2 := operatorsv1alpha1.ClusterServiceVersion{ - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ + // Create CSVs for the hat-server + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, + Name: depName, + Spec: depSpec, }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, + }, + } + + owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds)) + for i, kind := range mockKinds { + owned[i] = operatorsv1alpha1.APIServiceDescription{ + Name: apiServiceName, + Group: mockGroup, + Version: version, + Kind: kind, + DeploymentName: depName, + ContainerPort: int32(5443), + DisplayName: kind, + Description: fmt.Sprintf("A %s", kind), + } + } + + csv := operatorsv1alpha1.ClusterServiceVersion{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ + Owned: owned, }, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, - }, - APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ - Owned: owned, - }, - }, - } - csv2.SetName("csv-hat-2") - - // Create CSV2 to replace CSV - _, err = createCSV(c, crc, csv2, secondNamespaceName, false, true) - Expect(err).ShouldNot(HaveOccurred()) + } + csv.SetName("csv-hat-1") - _, err = fetchCSV(crc, csv2.Name, secondNamespaceName, csvFailedChecker) - Expect(err).ShouldNot(HaveOccurred()) - }) - It("orphaned API service clean up", func() { + // Create the initial CSV + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName("")) - version := "v1alpha1" - apiServiceName := strings.Join([]string{version, mockGroup}, ".") + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - apiService := &apiregistrationv1.APIService{ - ObjectMeta: metav1.ObjectMeta{ - Name: apiServiceName, - }, - Spec: apiregistrationv1.APIServiceSpec{ - Group: mockGroup, - Version: version, - GroupPriorityMinimum: 100, - VersionPriority: 100, - }, - } + // Should create Deployment + _, err = c.GetDeployment(ns.GetName(), depName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected Deployment") - watcher, err := c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Watch(context.TODO(), metav1.ListOptions{FieldSelector: "metadata.name=" + apiServiceName}) - Expect(err).ShouldNot(HaveOccurred()) + // Should create APIService + _, err = c.GetAPIService(apiServiceName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService") - deleted := make(chan struct{}) - quit := make(chan struct{}) - defer close(quit) - go func() { - defer GinkgoRecover() - events := watcher.ResultChan() - for { - select { - case <-quit: - return - case evt := <-events: - if evt.Type == watch.Deleted { - deleted <- struct{}{} - } - case <-time.After(pollDuration): - Fail("orphaned apiservice not cleaned up as expected") - } - } - }() - - _, err = c.CreateAPIService(apiService) - Expect(err).ShouldNot(HaveOccurred(), "error creating expected APIService") - orphanedAPISvc, err := c.GetAPIService(apiServiceName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService") - - newLabels := map[string]string{"olm.owner": "hat-serverfd4r5", "olm.owner.kind": "ClusterServiceVersion", "olm.owner.namespace": "nonexistent-namespace"} - orphanedAPISvc.SetLabels(newLabels) - _, err = c.UpdateAPIService(orphanedAPISvc) - Expect(err).ShouldNot(HaveOccurred(), "error updating APIService") - <-deleted - - _, err = c.CreateAPIService(apiService) - Expect(err).ShouldNot(HaveOccurred(), "error creating expected APIService") - orphanedAPISvc, err = c.GetAPIService(apiServiceName) - Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService") - - newLabels = map[string]string{"olm.owner": "hat-serverfd4r5", "olm.owner.kind": "ClusterServiceVersion", "olm.owner.namespace": testNamespace} - orphanedAPISvc.SetLabels(newLabels) - _, err = c.UpdateAPIService(orphanedAPISvc) - Expect(err).ShouldNot(HaveOccurred(), "error updating APIService") - <-deleted - }) - It("CSV annotations overwrite pod template annotations defined in a StrategyDetailsDeployment", func() { - // Create a StrategyDetailsDeployment that defines the `foo1` and `foo2` annotations on a pod template - nginxName := genName("nginx-") - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: genName("dep-"), - Spec: newNginxDeployment(nginxName), - }, - }, - } - strategy.DeploymentSpecs[0].Spec.Template.Annotations = map[string]string{ - "foo1": "notBar1", - "foo2": "bar2", - } + // Should create Service + serviceName := fmt.Sprintf("%s-service", depName) + _, err = c.GetService(ns.GetName(), serviceName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected Service") - // Create a CSV that defines the `foo1` and `foo3` annotations - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - Annotations: map[string]string{ - "foo1": "bar1", - "foo3": "bar3", - }, - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, - }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, - }, - }, - } + // Should create certificate Secret + secretName := fmt.Sprintf("%s-cert", serviceName) + _, err = c.GetSecret(ns.GetName(), secretName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret") - // Create the CSV and make sure to clean it up - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() + // Should create a Role for the Secret + _, err = c.GetRole(ns.GetName(), secretName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected Secret Role") - // Wait for current CSV to succeed - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + // Should create a RoleBinding for the Secret + _, err = c.GetRoleBinding(ns.GetName(), secretName) + Expect(err).ShouldNot(HaveOccurred(), "error getting exptected Secret RoleBinding") - // Should have created deployment - dep, err := c.GetDeployment(testNamespace, strategy.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(dep).ShouldNot(BeNil()) + // Should create a system:auth-delegator Cluster RoleBinding + _, err = c.GetClusterRoleBinding(fmt.Sprintf("%s-system:auth-delegator", serviceName)) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected system:auth-delegator ClusterRoleBinding") - // Make sure that the pods annotations are correct - annotations := dep.Spec.Template.Annotations - Expect(annotations["foo1"]).Should(Equal("bar1")) - Expect(annotations["foo2"]).Should(Equal("bar2")) - Expect(annotations["foo3"]).Should(Equal("bar3")) - }) - It("Set labels for the Deployment created via the ClusterServiceVersion", func() { - // Create a StrategyDetailsDeployment that defines labels for Deployment inside - nginxName := genName("nginx-") - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: genName("dep-"), - Spec: newNginxDeployment(nginxName), - Label: k8slabels.Set{ - "application": "nginx", - "application.type": "proxy", - }, - }, - }, - } + // Should create an extension-apiserver-authentication-reader RoleBinding in kube-system + _, err = c.GetRoleBinding("kube-system", fmt.Sprintf("%s-auth-reader", serviceName)) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected extension-apiserver-authentication-reader RoleBinding") - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, + // Create a new CSV that owns the same API Service but in a different namespace + csv2 := operatorsv1alpha1.ClusterServiceVersion{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ + Owned: owned, }, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, - }, - }, - } + } + csv2.SetName("csv-hat-2") - // Create the CSV and make sure to clean it up - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() + // Create CSV2 to replace CSV + _, err = createCSV(c, crc, csv2, secondNamespaceName, false, true) + Expect(err).ShouldNot(HaveOccurred()) - // Wait for current CSV to succeed - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + _, err = fetchCSV(crc, csv2.Name, secondNamespaceName, csvFailedChecker) + Expect(err).ShouldNot(HaveOccurred()) + }) + It("orphaned API service clean up", func() { - // Should have created deployment - dep, err := c.GetDeployment(testNamespace, strategy.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(dep).ShouldNot(BeNil()) - - // Make sure that the deployment labels are correct - labels := dep.GetLabels() - Expect(labels["olm.owner"]).Should(Equal(csv.GetName())) - Expect(labels["olm.owner.namespace"]).Should(Equal(testNamespace)) - Expect(labels["application"]).Should(Equal("nginx")) - Expect(labels["application.type"]).Should(Equal("proxy")) - }) - It("update same deployment name", func() { + mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName("")) + version := "v1alpha1" + apiServiceName := strings.Join([]string{version, mockGroup}, ".") - // Create dependency first (CRD) - crdPlural := genName("ins") - crdName := crdPlural + ".cluster.com" - cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{ - Name: crdName, - }, - Spec: apiextensions.CustomResourceDefinitionSpec{ - Group: "cluster.com", - Versions: []apiextensions.CustomResourceDefinitionVersion{ - { - Name: "v1alpha1", - Served: true, - Storage: true, - Schema: &apiextensions.CustomResourceValidation{ - OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ - Type: "object", - Description: "my crd schema", - }, - }, - }, + apiService := &apiregistrationv1.APIService{ + ObjectMeta: metav1.ObjectMeta{ + Name: apiServiceName, }, - Names: apiextensions.CustomResourceDefinitionNames{ - Plural: crdPlural, - Singular: crdPlural, - Kind: crdPlural, - ListKind: "list" + crdPlural, + Spec: apiregistrationv1.APIServiceSpec{ + Group: mockGroup, + Version: version, + GroupPriorityMinimum: 100, + VersionPriority: 100, }, - Scope: apiextensions.NamespaceScoped, - }, - }) + } - // Create "current" CSV - nginxName := genName("nginx-") - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: genName("dep-"), - Spec: newNginxDeployment(nginxName), - }, - }, - } + watcher, err := c.ApiregistrationV1Interface().ApiregistrationV1().APIServices().Watch(context.TODO(), metav1.ListOptions{FieldSelector: "metadata.name=" + apiServiceName}) + Expect(err).ShouldNot(HaveOccurred()) - Expect(err).ShouldNot(HaveOccurred()) + deleted := make(chan struct{}) + quit := make(chan struct{}) + defer close(quit) + go func() { + defer GinkgoRecover() + events := watcher.ResultChan() + for { + select { + case <-quit: + return + case evt := <-events: + if evt.Type == watch.Deleted { + deleted <- struct{}{} + } + case <-time.After(pollDuration): + Fail("orphaned apiservice not cleaned up as expected") + } + } + }() - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCRD() - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, + _, err = c.CreateAPIService(apiService) + Expect(err).ShouldNot(HaveOccurred(), "error creating expected APIService") + orphanedAPISvc, err := c.GetAPIService(apiServiceName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService") + + newLabels := map[string]string{"olm.owner": "hat-serverfd4r5", "olm.owner.kind": "ClusterServiceVersion", "olm.owner.namespace": "nonexistent-namespace"} + orphanedAPISvc.SetLabels(newLabels) + _, err = c.UpdateAPIService(orphanedAPISvc) + Expect(err).ShouldNot(HaveOccurred(), "error updating APIService") + <-deleted + + _, err = c.CreateAPIService(apiService) + Expect(err).ShouldNot(HaveOccurred(), "error creating expected APIService") + orphanedAPISvc, err = c.GetAPIService(apiServiceName) + Expect(err).ShouldNot(HaveOccurred(), "error getting expected APIService") + + newLabels = map[string]string{"olm.owner": "hat-serverfd4r5", "olm.owner.kind": "ClusterServiceVersion", "olm.owner.namespace": ns.GetName()} + orphanedAPISvc.SetLabels(newLabels) + _, err = c.UpdateAPIService(orphanedAPISvc) + Expect(err).ShouldNot(HaveOccurred(), "error updating APIService") + <-deleted + }) + It("CSV annotations overwrite pod template annotations defined in a StrategyDetailsDeployment", func() { + // Create a StrategyDetailsDeployment that defines the `foo1` and `foo2` annotations on a pod template + nginxName := genName("nginx-") + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + Name: genName("dep-"), + Spec: newNginxDeployment(nginxName), }, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, + } + strategy.DeploymentSpecs[0].Spec.Template.Annotations = map[string]string{ + "foo1": "notBar1", + "foo2": "bar2", + } + + // Create a CSV that defines the `foo1` and `foo3` annotations + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), + Annotations: map[string]string{ + "foo1": "bar1", + "foo3": "bar3", + }, }, - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ { - Name: crdName, - Version: "v1alpha1", - Kind: crdPlural, - DisplayName: crdName, - Description: "In the cluster", + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, }, }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, + }, }, - }, - } + } - // Don't need to cleanup this CSV, it will be deleted by the upgrade process - _, err = createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) + // Create the CSV and make sure to clean it up + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - // Wait for current CSV to succeed - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + // Wait for current CSV to succeed + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - // Should have created deployment - dep, err := c.GetDeployment(testNamespace, strategy.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(dep).ShouldNot(BeNil()) + // Should have created deployment + dep, err := c.GetDeployment(ns.GetName(), strategy.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(dep).ShouldNot(BeNil()) - // Create "updated" CSV - strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - // Same name - Name: strategy.DeploymentSpecs[0].Name, - // Different spec - Spec: newNginxDeployment(nginxName), + // Make sure that the pods annotations are correct + annotations := dep.Spec.Template.Annotations + Expect(annotations["foo1"]).Should(Equal("bar1")) + Expect(annotations["foo2"]).Should(Equal("bar2")) + Expect(annotations["foo3"]).Should(Equal("bar3")) + }) + It("Set labels for the Deployment created via the ClusterServiceVersion", func() { + // Create a StrategyDetailsDeployment that defines labels for Deployment inside + nginxName := genName("nginx-") + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ + { + Name: genName("dep-"), + Spec: newNginxDeployment(nginxName), + Label: k8slabels.Set{ + "application": "nginx", + "application.type": "proxy", + }, + }, }, - }, - } - - Expect(err).ShouldNot(HaveOccurred()) + } - csvNew := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - Replaces: csv.Name, - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategyNew, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), }, - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, { - Name: crdName, - Version: "v1alpha1", - Kind: crdPlural, - DisplayName: crdName, - Description: "In the cluster", + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, }, }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, + }, }, - }, - } - - cleanupNewCSV, err := createCSV(c, crc, csvNew, testNamespace, true, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupNewCSV() - - // Wait for updated CSV to succeed - fetchedCSV, err := fetchCSV(crc, csvNew.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + } - // Should have updated existing deployment - depUpdated, err := c.GetDeployment(testNamespace, strategyNew.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(depUpdated).ShouldNot(BeNil()) - Expect(strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Name).Should(Equal(depUpdated.Spec.Template.Spec.Containers[0].Name)) + // Create the CSV and make sure to clean it up + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - // Should eventually GC the CSV - Eventually(func() bool { - return csvExists(crc, csv.Name) - }).Should(BeFalse()) + // Wait for current CSV to succeed + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - // Fetch cluster service version again to check for unnecessary control loops - sameCSV, err := fetchCSV(crc, csvNew.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) - Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV)) - }) - It("update different deployment name", func() { + // Should have created deployment + dep, err := c.GetDeployment(ns.GetName(), strategy.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(dep).ShouldNot(BeNil()) + + // Make sure that the deployment labels are correct + labels := dep.GetLabels() + Expect(labels["olm.owner"]).Should(Equal(csv.GetName())) + Expect(labels["olm.owner.namespace"]).Should(Equal(ns.GetName())) + Expect(labels["application"]).Should(Equal("nginx")) + Expect(labels["application.type"]).Should(Equal("proxy")) + }) + It("update same deployment name", func() { - // Create dependency first (CRD) - crdPlural := genName("ins2") - crdName := crdPlural + ".cluster.com" - cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{ - Name: crdName, - }, - Spec: apiextensions.CustomResourceDefinitionSpec{ - Group: "cluster.com", - Versions: []apiextensions.CustomResourceDefinitionVersion{ - { - Name: "v1alpha1", - Served: true, - Storage: true, - Schema: &apiextensions.CustomResourceValidation{ - OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ - Type: "object", - Description: "my crd schema", + // Create dependency first (CRD) + crdPlural := genName("ins") + crdName := crdPlural + ".cluster.com" + cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: crdName, + }, + Spec: apiextensions.CustomResourceDefinitionSpec{ + Group: "cluster.com", + Versions: []apiextensions.CustomResourceDefinitionVersion{ + { + Name: "v1alpha1", + Served: true, + Storage: true, + Schema: &apiextensions.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ + Type: "object", + Description: "my crd schema", + }, }, }, }, + Names: apiextensions.CustomResourceDefinitionNames{ + Plural: crdPlural, + Singular: crdPlural, + Kind: crdPlural, + ListKind: "list" + crdPlural, + }, + Scope: apiextensions.NamespaceScoped, }, - Names: apiextensions.CustomResourceDefinitionNames{ - Plural: crdPlural, - Singular: crdPlural, - Kind: crdPlural, - ListKind: "list" + crdPlural, - }, - Scope: apiextensions.NamespaceScoped, - }, - }) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCRD() + }) - // create "current" CSV - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: genName("dep-"), - Spec: newNginxDeployment(genName("nginx-")), + // Create "current" CSV + nginxName := genName("nginx-") + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ + { + Name: genName("dep-"), + Spec: newNginxDeployment(nginxName), + }, }, - }, - } + } - Expect(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCRD() + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), }, - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, { - Name: crdName, - Version: "v1alpha1", - Kind: crdPlural, - DisplayName: crdName, - Description: "In the cluster2", + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, + }, + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "v1alpha1", + Kind: crdPlural, + DisplayName: crdName, + Description: "In the cluster", + }, }, }, }, - }, - } + } - // don't need to clean up this CSV, it will be deleted by the upgrade process - _, err = createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) + // Don't need to cleanup this CSV, it will be deleted by the upgrade process + _, err = createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) - // Wait for current CSV to succeed - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + // Wait for current CSV to succeed + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - // Should have created deployment - dep, err := c.GetDeployment(testNamespace, strategy.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(dep).ShouldNot(BeNil()) + // Should have created deployment + dep, err := c.GetDeployment(ns.GetName(), strategy.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(dep).ShouldNot(BeNil()) - // Create "updated" CSV - strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: genName("dep2"), - Spec: newNginxDeployment(genName("nginx-")), + // Create "updated" CSV + strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ + { + // Same name + Name: strategy.DeploymentSpecs[0].Name, + // Different spec + Spec: newNginxDeployment(nginxName), + }, }, - }, - } + } - Expect(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - csvNew := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv2"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - Replaces: csv.Name, - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, + csvNew := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategyNew, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), }, - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + Replaces: csv.Name, + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, { - Name: crdName, - Version: "v1alpha1", - Kind: crdPlural, - DisplayName: crdName, - Description: "In the cluster2", + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategyNew, + }, + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "v1alpha1", + Kind: crdPlural, + DisplayName: crdName, + Description: "In the cluster", + }, }, }, }, - }, - } + } - cleanupNewCSV, err := createCSV(c, crc, csvNew, testNamespace, true, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupNewCSV() + cleanupNewCSV, err := createCSV(c, crc, csvNew, ns.GetName(), true, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupNewCSV() - // Wait for updated CSV to succeed - fetchedCSV, err := fetchCSV(crc, csvNew.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + // Wait for updated CSV to succeed + fetchedCSV, err := fetchCSV(crc, csvNew.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - // Fetch cluster service version again to check for unnecessary control loops - sameCSV, err := fetchCSV(crc, csvNew.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) - Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV)) + // Should have updated existing deployment + depUpdated, err := c.GetDeployment(ns.GetName(), strategyNew.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(depUpdated).ShouldNot(BeNil()) + Expect(strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Name).Should(Equal(depUpdated.Spec.Template.Spec.Containers[0].Name)) - // Should have created new deployment and deleted old - depNew, err := c.GetDeployment(testNamespace, strategyNew.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(depNew).ShouldNot(BeNil()) - err = waitForDeploymentToDelete(c, strategy.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) + // Should eventually GC the CSV + Eventually(func() bool { + return csvExists(ns.GetName(), crc, csv.Name) + }).Should(BeFalse()) - // Should eventually GC the CSV - Eventually(func() bool { - return csvExists(crc, csv.Name) - }).Should(BeFalse()) - }) - It("update multiple intermediates", func() { + // Fetch cluster service version again to check for unnecessary control loops + sameCSV, err := fetchCSV(crc, csvNew.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) + Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV)) + }) + It("update different deployment name", func() { - // Create dependency first (CRD) - crdPlural := genName("ins3") - crdName := crdPlural + ".cluster.com" - cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{ - Name: crdName, - }, - Spec: apiextensions.CustomResourceDefinitionSpec{ - Group: "cluster.com", - Versions: []apiextensions.CustomResourceDefinitionVersion{ - { - Name: "v1alpha1", - Served: true, - Storage: true, - Schema: &apiextensions.CustomResourceValidation{ - OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ - Type: "object", - Description: "my crd schema", + // Create dependency first (CRD) + crdPlural := genName("ins2") + crdName := crdPlural + ".cluster.com" + cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: crdName, + }, + Spec: apiextensions.CustomResourceDefinitionSpec{ + Group: "cluster.com", + Versions: []apiextensions.CustomResourceDefinitionVersion{ + { + Name: "v1alpha1", + Served: true, + Storage: true, + Schema: &apiextensions.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ + Type: "object", + Description: "my crd schema", + }, }, }, }, + Names: apiextensions.CustomResourceDefinitionNames{ + Plural: crdPlural, + Singular: crdPlural, + Kind: crdPlural, + ListKind: "list" + crdPlural, + }, + Scope: apiextensions.NamespaceScoped, }, - Names: apiextensions.CustomResourceDefinitionNames{ - Plural: crdPlural, - Singular: crdPlural, - Kind: crdPlural, - ListKind: "list" + crdPlural, - }, - Scope: apiextensions.NamespaceScoped, - }, - }) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCRD() + }) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCRD() - // create "current" CSV - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: genName("dep-"), - Spec: newNginxDeployment(genName("nginx-")), + // create "current" CSV + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ + { + Name: genName("dep-"), + Spec: newNginxDeployment(genName("nginx-")), + }, }, - }, - } + } - Expect(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), }, - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ { - Name: crdName, - Version: "v1alpha1", - Kind: crdPlural, - DisplayName: crdName, - Description: "In the cluster3", + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, }, }, - }, - }, - } - - // don't need to clean up this CSV, it will be deleted by the upgrade process - _, err = createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) - - // Wait for current CSV to succeed - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) - - // Should have created deployment - dep, err := c.GetDeployment(testNamespace, strategy.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(dep).ShouldNot(BeNil()) - - // Create "updated" CSV - strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: genName("dep2"), - Spec: newNginxDeployment(genName("nginx-")), - }, - }, - } - - Expect(err).ShouldNot(HaveOccurred()) - - csvNew := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv2"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - Replaces: csv.Name, - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, }, - }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategyNew, - }, - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ - { - Name: crdName, - Version: "v1alpha1", - Kind: crdPlural, - DisplayName: crdName, - Description: "In the cluster3", + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "v1alpha1", + Kind: crdPlural, + DisplayName: crdName, + Description: "In the cluster2", + }, }, }, }, - }, - } - - cleanupNewCSV, err := createCSV(c, crc, csvNew, testNamespace, true, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupNewCSV() - - // Wait for updated CSV to succeed - fetchedCSV, err := fetchCSV(crc, csvNew.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + } - // Fetch cluster service version again to check for unnecessary control loops - sameCSV, err := fetchCSV(crc, csvNew.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) - Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV)) + // don't need to clean up this CSV, it will be deleted by the upgrade process + _, err = createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) - // Should have created new deployment and deleted old - depNew, err := c.GetDeployment(testNamespace, strategyNew.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(depNew).ShouldNot(BeNil()) - err = waitForDeploymentToDelete(c, strategy.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) + // Wait for current CSV to succeed + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - // Should eventually GC the CSV - Eventually(func() bool { - return csvExists(crc, csv.Name) - }).Should(BeFalse()) - }) - It("update in place", func() { + // Should have created deployment + dep, err := c.GetDeployment(ns.GetName(), strategy.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(dep).ShouldNot(BeNil()) - // Create dependency first (CRD) - crdPlural := genName("ins") - crdName := crdPlural + ".cluster.com" - cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{ - Name: crdName, - }, - Spec: apiextensions.CustomResourceDefinitionSpec{ - Group: "cluster.com", - Versions: []apiextensions.CustomResourceDefinitionVersion{ + // Create "updated" CSV + strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ { - Name: "v1alpha1", - Served: true, - Storage: true, - Schema: &apiextensions.CustomResourceValidation{ - OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ - Type: "object", - Description: "my crd schema", - }, - }, + Name: genName("dep2"), + Spec: newNginxDeployment(genName("nginx-")), }, }, - Names: apiextensions.CustomResourceDefinitionNames{ - Plural: crdPlural, - Singular: crdPlural, - Kind: crdPlural, - ListKind: "list" + crdPlural, - }, - Scope: apiextensions.NamespaceScoped, - }, - }) - - // Create "current" CSV - nginxName := genName("nginx-") - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: genName("dep-"), - Spec: newNginxDeployment(nginxName), - }, - }, - } + } - Expect(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCRD() - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, + csvNew := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv2"), }, - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + Replaces: csv.Name, + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, { - Name: crdName, - Version: "v1alpha1", - Kind: crdPlural, - DisplayName: crdName, - Description: "In the cluster", + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, }, }, - }, - }, - } - - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, true) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() - - // Wait for current CSV to succeed - fetchedCSV, err := fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) - - // Should have created deployment - dep, err := c.GetDeployment(testNamespace, strategy.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(dep).ShouldNot(BeNil()) - - // Create "updated" CSV - strategyNew := strategy - strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers = []corev1.Container{ - { - Name: genName("nginx-"), - Image: *dummyImage, - Ports: []corev1.ContainerPort{ - { - ContainerPort: 80, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategyNew, + }, + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "v1alpha1", + Kind: crdPlural, + DisplayName: crdName, + Description: "In the cluster2", + }, + }, }, }, - ImagePullPolicy: corev1.PullIfNotPresent, - }, - } - - // Also set something outside the spec template - this should be ignored - var five int32 = 5 - strategyNew.DeploymentSpecs[0].Spec.Replicas = &five - - Expect(err).ShouldNot(HaveOccurred()) - - fetchedCSV.Spec.InstallStrategy.StrategySpec = strategyNew - - // Update CSV directly - _, err = crc.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Update(context.TODO(), fetchedCSV, metav1.UpdateOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - - // wait for deployment spec to be updated - Eventually(func() (string, error) { - fetched, err := c.GetDeployment(testNamespace, strategyNew.DeploymentSpecs[0].Name) - if err != nil { - return "", err } - ctx.Ctx().Logf("waiting for deployment to update...") - return fetched.Spec.Template.Spec.Containers[0].Name, nil - }).Should(Equal(strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Name)) - // Wait for updated CSV to succeed - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + cleanupNewCSV, err := createCSV(c, crc, csvNew, ns.GetName(), true, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupNewCSV() - depUpdated, err := c.GetDeployment(testNamespace, strategyNew.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(depUpdated).ShouldNot(BeNil()) + // Wait for updated CSV to succeed + fetchedCSV, err := fetchCSV(crc, csvNew.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - // Deployment should have changed even though the CSV is otherwise the same - Expect(strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Name).Should(Equal(depUpdated.Spec.Template.Spec.Containers[0].Name)) - Expect(strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Image).Should(Equal(depUpdated.Spec.Template.Spec.Containers[0].Image)) + // Fetch cluster service version again to check for unnecessary control loops + sameCSV, err := fetchCSV(crc, csvNew.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) + Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV)) - // Field updated even though template spec didn't change, because it was part of a template spec change as well - Expect(*strategyNew.DeploymentSpecs[0].Spec.Replicas).Should(Equal(*depUpdated.Spec.Replicas)) - }) - It("update multiple version CRD", func() { + // Should have created new deployment and deleted old + depNew, err := c.GetDeployment(ns.GetName(), strategyNew.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(depNew).ShouldNot(BeNil()) + err = waitForDeploymentToDelete(ns.GetName(), c, strategy.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) - // Create initial CRD which has 2 versions: v1alpha1 & v1alpha2 - crdPlural := genName("ins4") - crdName := crdPlural + ".cluster.com" - cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{ - Name: crdName, - }, - Spec: apiextensions.CustomResourceDefinitionSpec{ - Group: "cluster.com", - Versions: []apiextensions.CustomResourceDefinitionVersion{ - { - Name: "v1alpha1", - Served: true, - Storage: true, - Schema: &apiextensions.CustomResourceValidation{ - OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ - Type: "object", - Description: "my crd schema", + // Should eventually GC the CSV + Eventually(func() bool { + return csvExists(ns.GetName(), crc, csv.Name) + }).Should(BeFalse()) + }) + It("update multiple intermediates", func() { + + // Create dependency first (CRD) + crdPlural := genName("ins3") + crdName := crdPlural + ".cluster.com" + cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: crdName, + }, + Spec: apiextensions.CustomResourceDefinitionSpec{ + Group: "cluster.com", + Versions: []apiextensions.CustomResourceDefinitionVersion{ + { + Name: "v1alpha1", + Served: true, + Storage: true, + Schema: &apiextensions.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ + Type: "object", + Description: "my crd schema", + }, }, }, }, - { - Name: "v1alpha2", - Served: true, - Storage: false, - Schema: &apiextensions.CustomResourceValidation{ - OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ - Type: "object", - Description: "my crd schema", - }, - }, + Names: apiextensions.CustomResourceDefinitionNames{ + Plural: crdPlural, + Singular: crdPlural, + Kind: crdPlural, + ListKind: "list" + crdPlural, }, + Scope: apiextensions.NamespaceScoped, }, - Names: apiextensions.CustomResourceDefinitionNames{ - Plural: crdPlural, - Singular: crdPlural, - Kind: crdPlural, - ListKind: "list" + crdPlural, - }, - Scope: apiextensions.NamespaceScoped, - }, - }) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCRD() + }) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCRD() - // create initial deployment strategy - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: genName("dep1-"), - Spec: newNginxDeployment(genName("nginx-")), + // create "current" CSV + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ + { + Name: genName("dep-"), + Spec: newNginxDeployment(genName("nginx-")), + }, }, - }, - } + } - Expect(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - // First CSV with owning CRD v1alpha1 - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), + }, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "v1alpha1", + Kind: crdPlural, + DisplayName: crdName, + Description: "In the cluster3", + }, + }, }, + }, + } + + // don't need to clean up this CSV, it will be deleted by the upgrade process + _, err = createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) + + // Wait for current CSV to succeed + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) + + // Should have created deployment + dep, err := c.GetDeployment(ns.GetName(), strategy.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(dep).ShouldNot(BeNil()) + + // Create "updated" CSV + strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + Name: genName("dep2"), + Spec: newNginxDeployment(genName("nginx-")), }, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, + } + + Expect(err).ShouldNot(HaveOccurred()) + + csvNew := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv2"), }, - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + Replaces: csv.Name, + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, { - Name: crdName, - Version: "v1alpha1", - Kind: crdPlural, - DisplayName: crdName, - Description: "In the cluster4", + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategyNew, + }, + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "v1alpha1", + Kind: crdPlural, + DisplayName: crdName, + Description: "In the cluster3", + }, }, }, }, - }, - } + } - // CSV will be deleted by the upgrade process later - _, err = createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) + cleanupNewCSV, err := createCSV(c, crc, csvNew, ns.GetName(), true, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupNewCSV() - // Wait for current CSV to succeed - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + // Wait for updated CSV to succeed + fetchedCSV, err := fetchCSV(crc, csvNew.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - // Should have created deployment - dep, err := c.GetDeployment(testNamespace, strategy.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(dep).ShouldNot(BeNil()) + // Fetch cluster service version again to check for unnecessary control loops + sameCSV, err := fetchCSV(crc, csvNew.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) + Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV)) - // Create updated deployment strategy - strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: genName("dep2-"), - Spec: newNginxDeployment(genName("nginx-")), - }, - }, - } + // Should have created new deployment and deleted old + depNew, err := c.GetDeployment(ns.GetName(), strategyNew.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(depNew).ShouldNot(BeNil()) + err = waitForDeploymentToDelete(ns.GetName(), c, strategy.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) - Expect(err).ShouldNot(HaveOccurred()) + // Should eventually GC the CSV + Eventually(func() bool { + return csvExists(ns.GetName(), crc, csv.Name) + }).Should(BeFalse()) + }) + It("update in place", func() { - // Second CSV with owning CRD v1alpha1 and v1alpha2 - csvNew := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv2"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - Replaces: csv.Name, - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, + // Create dependency first (CRD) + crdPlural := genName("ins") + crdName := crdPlural + ".cluster.com" + cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: crdName, + }, + Spec: apiextensions.CustomResourceDefinitionSpec{ + Group: "cluster.com", + Versions: []apiextensions.CustomResourceDefinitionVersion{ + { + Name: "v1alpha1", + Served: true, + Storage: true, + Schema: &apiextensions.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ + Type: "object", + Description: "my crd schema", + }, + }, + }, }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, + Names: apiextensions.CustomResourceDefinitionNames{ + Plural: crdPlural, + Singular: crdPlural, + Kind: crdPlural, + ListKind: "list" + crdPlural, }, + Scope: apiextensions.NamespaceScoped, + }, + }) + + // Create "current" CSV + nginxName := genName("nginx-") + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + Name: genName("dep-"), + Spec: newNginxDeployment(nginxName), }, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategyNew, + } + + Expect(err).ShouldNot(HaveOccurred()) + + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCRD() + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), }, - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, { - Name: crdName, - Version: "v1alpha1", - Kind: crdPlural, - DisplayName: crdName, - Description: "In the cluster4", + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, }, { - Name: crdName, - Version: "v1alpha2", - Kind: crdPlural, - DisplayName: crdName, - Description: "In the cluster4", + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, + }, + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "v1alpha1", + Kind: crdPlural, + DisplayName: crdName, + Description: "In the cluster", + }, }, }, }, - }, - } - - // Create newly updated CSV - _, err = createCSV(c, crc, csvNew, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) + } - // Wait for updated CSV to succeed - fetchedCSV, err := fetchCSV(crc, csvNew.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, true) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - // Fetch cluster service version again to check for unnecessary control loops - sameCSV, err := fetchCSV(crc, csvNew.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) - Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV)) + // Wait for current CSV to succeed + fetchedCSV, err := fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - // Should have created new deployment and deleted old one - depNew, err := c.GetDeployment(testNamespace, strategyNew.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(depNew).ShouldNot(BeNil()) - err = waitForDeploymentToDelete(c, strategy.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) + // Should have created deployment + dep, err := c.GetDeployment(ns.GetName(), strategy.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(dep).ShouldNot(BeNil()) - // Create updated deployment strategy - strategyNew2 := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ + // Create "updated" CSV + strategyNew := strategy + strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers = []corev1.Container{ { - Name: genName("dep3-"), - Spec: newNginxDeployment(genName("nginx-")), - }, - }, - } - Expect(err).ShouldNot(HaveOccurred()) - - // Third CSV with owning CRD v1alpha2 - csvNew2 := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv3"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - Replaces: csvNew.Name, - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, - }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategyNew2, - }, - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ + Name: genName("nginx-"), + Image: *dummyImage, + Ports: []corev1.ContainerPort{ { - Name: crdName, - Version: "v1alpha2", - Kind: crdPlural, - DisplayName: crdName, - Description: "In the cluster4", + ContainerPort: 80, }, }, + ImagePullPolicy: corev1.PullIfNotPresent, }, - }, - } + } - // Create newly updated CSV - cleanupNewCSV, err := createCSV(c, crc, csvNew2, testNamespace, true, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupNewCSV() + // Also set something outside the spec template - this should be ignored + var five int32 = 5 + strategyNew.DeploymentSpecs[0].Spec.Replicas = &five - // Wait for updated CSV to succeed - fetchedCSV, err = fetchCSV(crc, csvNew2.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - // Fetch cluster service version again to check for unnecessary control loops - sameCSV, err = fetchCSV(crc, csvNew2.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) - Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV)) + fetchedCSV.Spec.InstallStrategy.StrategySpec = strategyNew - // Should have created new deployment and deleted old one - depNew, err = c.GetDeployment(testNamespace, strategyNew2.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(depNew).ShouldNot(BeNil()) - err = waitForDeploymentToDelete(c, strategyNew.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) + // Update CSV directly + _, err = crc.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Update(context.TODO(), fetchedCSV, metav1.UpdateOptions{}) + Expect(err).ShouldNot(HaveOccurred()) - // Should clean up the CSV - Eventually(func() bool { - return csvExists(crc, csvNew.Name) - }).Should(BeFalse()) - }) - It("update modify deployment name", func() { + // wait for deployment spec to be updated + Eventually(func() (string, error) { + fetched, err := c.GetDeployment(ns.GetName(), strategyNew.DeploymentSpecs[0].Name) + if err != nil { + return "", err + } + ctx.Ctx().Logf("waiting for deployment to update...") + return fetched.Spec.Template.Spec.Containers[0].Name, nil + }).Should(Equal(strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Name)) - // Create dependency first (CRD) - crdPlural := genName("ins2") - crdName := crdPlural + ".cluster.com" - cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{ - Name: crdName, - }, - Spec: apiextensions.CustomResourceDefinitionSpec{ - Group: "cluster.com", - Versions: []apiextensions.CustomResourceDefinitionVersion{ - { - Name: "v1alpha1", - Served: true, - Storage: true, - Schema: &apiextensions.CustomResourceValidation{ - OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ - Type: "object", - Description: "my crd schema", + // Wait for updated CSV to succeed + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) + + depUpdated, err := c.GetDeployment(ns.GetName(), strategyNew.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(depUpdated).ShouldNot(BeNil()) + + // Deployment should have changed even though the CSV is otherwise the same + Expect(strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Name).Should(Equal(depUpdated.Spec.Template.Spec.Containers[0].Name)) + Expect(strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Image).Should(Equal(depUpdated.Spec.Template.Spec.Containers[0].Image)) + + // Field updated even though template spec didn't change, because it was part of a template spec change as well + Expect(*strategyNew.DeploymentSpecs[0].Spec.Replicas).Should(Equal(*depUpdated.Spec.Replicas)) + }) + It("update multiple version CRD", func() { + + // Create initial CRD which has 2 versions: v1alpha1 & v1alpha2 + crdPlural := genName("ins4") + crdName := crdPlural + ".cluster.com" + cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: crdName, + }, + Spec: apiextensions.CustomResourceDefinitionSpec{ + Group: "cluster.com", + Versions: []apiextensions.CustomResourceDefinitionVersion{ + { + Name: "v1alpha1", + Served: true, + Storage: true, + Schema: &apiextensions.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ + Type: "object", + Description: "my crd schema", + }, + }, + }, + { + Name: "v1alpha2", + Served: true, + Storage: false, + Schema: &apiextensions.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ + Type: "object", + Description: "my crd schema", + }, }, }, }, + Names: apiextensions.CustomResourceDefinitionNames{ + Plural: crdPlural, + Singular: crdPlural, + Kind: crdPlural, + ListKind: "list" + crdPlural, + }, + Scope: apiextensions.NamespaceScoped, }, - Names: apiextensions.CustomResourceDefinitionNames{ - Plural: crdPlural, - Singular: crdPlural, - Kind: crdPlural, - ListKind: "list" + crdPlural, - }, - Scope: apiextensions.NamespaceScoped, - }, - }) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCRD() + }) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCRD() - // create "current" CSV - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: genName("dep-"), - Spec: newNginxDeployment(genName("nginx-")), - }, - { - Name: "dep2-test", - Spec: newNginxDeployment("nginx2"), + // create initial deployment strategy + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ + { + Name: genName("dep1-"), + Spec: newNginxDeployment(genName("nginx-")), + }, }, - }, - } + } - Expect(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, + // First CSV with owning CRD v1alpha1 + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), }, - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, { - Name: crdName, - Version: "v1alpha1", - Kind: crdPlural, - DisplayName: crdName, - Description: "In the cluster2", + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, + }, + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "v1alpha1", + Kind: crdPlural, + DisplayName: crdName, + Description: "In the cluster4", + }, }, }, }, - }, - } + } - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, true, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() + // CSV will be deleted by the upgrade process later + _, err = createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) - // Wait for current CSV to succeed - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + // Wait for current CSV to succeed + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - // Should have created deployments - dep, err := c.GetDeployment(testNamespace, strategy.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(dep).ShouldNot(BeNil()) - dep2, err := c.GetDeployment(testNamespace, strategy.DeploymentSpecs[1].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(dep2).ShouldNot(BeNil()) + // Should have created deployment + dep, err := c.GetDeployment(ns.GetName(), strategy.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(dep).ShouldNot(BeNil()) - // Create "updated" CSV - strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: genName("dep3-"), - Spec: newNginxDeployment(genName("nginx3-")), - }, - { - Name: "dep2-test", - Spec: newNginxDeployment("nginx2"), + // Create updated deployment strategy + strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ + { + Name: genName("dep2-"), + Spec: newNginxDeployment(genName("nginx-")), + }, }, - }, - } - - Expect(err).ShouldNot(HaveOccurred()) - - // Fetch the current csv - fetchedCSV, err := fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) - - // Update csv with same strategy with different deployment's name - fetchedCSV.Spec.InstallStrategy.StrategySpec = strategyNew - - // Update the current csv with the new csv - _, err = crc.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Update(context.TODO(), fetchedCSV, metav1.UpdateOptions{}) - Expect(err).ShouldNot(HaveOccurred()) + } - // Wait for new deployment to exist - err = waitForDeployment(c, strategyNew.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - // Wait for updated CSV to succeed - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + // Second CSV with owning CRD v1alpha1 and v1alpha2 + csvNew := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv2"), + }, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + Replaces: csv.Name, + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategyNew, + }, + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "v1alpha1", + Kind: crdPlural, + DisplayName: crdName, + Description: "In the cluster4", + }, + { + Name: crdName, + Version: "v1alpha2", + Kind: crdPlural, + DisplayName: crdName, + Description: "In the cluster4", + }, + }, + }, + }, + } - // Should have created new deployment and deleted old - depNew, err := c.GetDeployment(testNamespace, strategyNew.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(depNew).ShouldNot(BeNil()) + // Create newly updated CSV + _, err = createCSV(c, crc, csvNew, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) - // Make sure the unchanged deployment still exists - depNew2, err := c.GetDeployment(testNamespace, strategyNew.DeploymentSpecs[1].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(depNew2).ShouldNot(BeNil()) + // Wait for updated CSV to succeed + fetchedCSV, err := fetchCSV(crc, csvNew.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - err = waitForDeploymentToDelete(c, strategy.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - }) - It("update deployment spec in an existing CSV for a hotfix", func() { + // Fetch cluster service version again to check for unnecessary control loops + sameCSV, err := fetchCSV(crc, csvNew.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) + Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV)) - c := newKubeClient() - crc := newCRClient() + // Should have created new deployment and deleted old one + depNew, err := c.GetDeployment(ns.GetName(), strategyNew.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(depNew).ShouldNot(BeNil()) + err = waitForDeploymentToDelete(ns.GetName(), c, strategy.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) - // Create dependency first (CRD) - crdPlural := genName("ins") - crdName := crdPlural + ".cluster.com" - cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{ - Name: crdName, - }, - Spec: apiextensions.CustomResourceDefinitionSpec{ - Group: "cluster.com", - Versions: []apiextensions.CustomResourceDefinitionVersion{ + // Create updated deployment strategy + strategyNew2 := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ { - Name: "v1alpha1", - Served: true, - Storage: true, - Schema: &apiextensions.CustomResourceValidation{ - OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ - Type: "object", - Description: "my crd schema", + Name: genName("dep3-"), + Spec: newNginxDeployment(genName("nginx-")), + }, + }, + } + Expect(err).ShouldNot(HaveOccurred()) + + // Third CSV with owning CRD v1alpha2 + csvNew2 := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv3"), + }, + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + Replaces: csvNew.Name, + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategyNew2, + }, + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "v1alpha2", + Kind: crdPlural, + DisplayName: crdName, + Description: "In the cluster4", }, }, }, }, - Names: apiextensions.CustomResourceDefinitionNames{ - Plural: crdPlural, - Singular: crdPlural, - Kind: crdPlural, - ListKind: "list" + crdPlural, - }, - Scope: apiextensions.NamespaceScoped, - }, - }) - defer cleanupCRD() - Expect(err).ShouldNot(HaveOccurred()) + } - // Create "current" CSV - nginxName := genName("nginx-") - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: genName("dep-"), - Spec: newNginxDeployment(nginxName), - }, - }, - } + // Create newly updated CSV + cleanupNewCSV, err := createCSV(c, crc, csvNew2, ns.GetName(), true, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupNewCSV() - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, + // Wait for updated CSV to succeed + fetchedCSV, err = fetchCSV(crc, csvNew2.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) + + // Fetch cluster service version again to check for unnecessary control loops + sameCSV, err = fetchCSV(crc, csvNew2.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) + Expect(equality.Semantic.DeepEqual(fetchedCSV, sameCSV)).Should(BeTrue(), diff.ObjectDiff(fetchedCSV, sameCSV)) + + // Should have created new deployment and deleted old one + depNew, err = c.GetDeployment(ns.GetName(), strategyNew2.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(depNew).ShouldNot(BeNil()) + err = waitForDeploymentToDelete(ns.GetName(), c, strategyNew.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + + // Should clean up the CSV + Eventually(func() bool { + return csvExists(ns.GetName(), crc, csvNew.Name) + }).Should(BeFalse()) + }) + + It("update modify deployment name", func() { + + // Create dependency first (CRD) + crdPlural := genName("ins2") + crdName := crdPlural + ".cluster.com" + cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: crdName, + }, + Spec: apiextensions.CustomResourceDefinitionSpec{ + Group: "cluster.com", + Versions: []apiextensions.CustomResourceDefinitionVersion{ + { + Name: "v1alpha1", + Served: true, + Storage: true, + Schema: &apiextensions.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ + Type: "object", + Description: "my crd schema", + }, + }, + }, }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, + Names: apiextensions.CustomResourceDefinitionNames{ + Plural: crdPlural, + Singular: crdPlural, + Kind: crdPlural, + ListKind: "list" + crdPlural, }, + Scope: apiextensions.NamespaceScoped, + }, + }) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCRD() + + // create "current" CSV + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, + Name: genName("dep-"), + Spec: newNginxDeployment(genName("nginx-")), }, { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + Name: "dep2-test", + Spec: newNginxDeployment("nginx2"), }, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, + } + + Expect(err).ShouldNot(HaveOccurred()) + + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), }, - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, { - Name: crdName, - Version: "v1alpha1", - Kind: crdPlural, - DisplayName: crdName, - Description: "In the cluster", + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, + }, + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "v1alpha1", + Kind: crdPlural, + DisplayName: crdName, + Description: "In the cluster2", + }, }, }, }, - }, - } + } - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, true, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), true, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - // Wait for current CSV to succeed - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + // Wait for current CSV to succeed + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - // Should have created deployment - dep, err := c.GetDeployment(testNamespace, strategy.DeploymentSpecs[0].Name) - Expect(err).ShouldNot(HaveOccurred()) - Expect(dep).ShouldNot(BeNil()) + // Should have created deployments + dep, err := c.GetDeployment(ns.GetName(), strategy.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(dep).ShouldNot(BeNil()) + dep2, err := c.GetDeployment(ns.GetName(), strategy.DeploymentSpecs[1].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(dep2).ShouldNot(BeNil()) - // Create "updated" CSV - strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - // Same name - Name: strategy.DeploymentSpecs[0].Name, - // Different spec - Spec: newNginxDeployment(nginxName), + // Create "updated" CSV + strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ + { + Name: genName("dep3-"), + Spec: newNginxDeployment(genName("nginx3-")), + }, + { + Name: "dep2-test", + Spec: newNginxDeployment("nginx2"), + }, }, - }, - } + } - // Fetch the current csv - fetchedCSV, err := fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + Expect(err).ShouldNot(HaveOccurred()) - // Update csv with modified deployment spec - fetchedCSV.Spec.InstallStrategy.StrategySpec = strategyNew + // Fetch the current csv + fetchedCSV, err := fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - Eventually(func() error { - // Update the current csv - _, err = crc.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Update(context.TODO(), fetchedCSV, metav1.UpdateOptions{}) - return err - }).Should(Succeed()) + // Update csv with same strategy with different deployment's name + fetchedCSV.Spec.InstallStrategy.StrategySpec = strategyNew - // Wait for updated CSV to succeed - _, err = fetchCSV(crc, csv.Name, testNamespace, func(csv *operatorsv1alpha1.ClusterServiceVersion) bool { + // Update the current csv with the new csv + _, err = crc.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Update(context.TODO(), fetchedCSV, metav1.UpdateOptions{}) + Expect(err).ShouldNot(HaveOccurred()) - // Should have updated existing deployment - depUpdated, err := c.GetDeployment(testNamespace, strategyNew.DeploymentSpecs[0].Name) + // Wait for new deployment to exist + err = waitForDeployment(ns.GetName(), c, strategyNew.DeploymentSpecs[0].Name) Expect(err).ShouldNot(HaveOccurred()) - Expect(depUpdated).ShouldNot(BeNil()) - // container name has been updated and differs from initial CSV spec and updated CSV spec - Expect(depUpdated.Spec.Template.Spec.Containers[0].Name).ShouldNot(Equal(strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Name)) - // Check for success - return csvSucceededChecker(csv) + // Wait for updated CSV to succeed + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) + + // Should have created new deployment and deleted old + depNew, err := c.GetDeployment(ns.GetName(), strategyNew.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(depNew).ShouldNot(BeNil()) + + // Make sure the unchanged deployment still exists + depNew2, err := c.GetDeployment(ns.GetName(), strategyNew.DeploymentSpecs[1].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(depNew2).ShouldNot(BeNil()) + + err = waitForDeploymentToDelete(ns.GetName(), c, strategy.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) }) - Expect(err).ShouldNot(HaveOccurred()) + It("update deployment spec in an existing CSV for a hotfix", func() { - }) - It("emits CSV requirement events", func() { + c := newKubeClient() + crc := newCRClient() - csv := &operatorsv1alpha1.ClusterServiceVersion{ - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, + // Create dependency first (CRD) + crdPlural := genName("ins") + crdName := crdPlural + ".cluster.com" + cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: crdName, }, - InstallStrategy: newNginxInstallStrategy(genName("dep-"), nil, nil), - APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ - // Require an API that we know won't exist under our domain - Required: []operatorsv1alpha1.APIServiceDescription{ + Spec: apiextensions.CustomResourceDefinitionSpec{ + Group: "cluster.com", + Versions: []apiextensions.CustomResourceDefinitionVersion{ { - Group: "bad.packages.operators.coreos.com", - Version: "v1", - Kind: "PackageManifest", + Name: "v1alpha1", + Served: true, + Storage: true, + Schema: &apiextensions.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ + Type: "object", + Description: "my crd schema", + }, + }, }, }, + Names: apiextensions.CustomResourceDefinitionNames{ + Plural: crdPlural, + Singular: crdPlural, + Kind: crdPlural, + ListKind: "list" + crdPlural, + }, + Scope: apiextensions.NamespaceScoped, }, - }, - } - csv.SetNamespace(testNamespace) - csv.SetName(genName("csv-")) - - clientCtx := context.Background() - listOpts := metav1.ListOptions{ - FieldSelector: "involvedObject.kind=ClusterServiceVersion", - } - events, err := c.KubernetesInterface().CoreV1().Events(csv.GetNamespace()).List(clientCtx, listOpts) - Expect(err).ToNot(HaveOccurred()) - - // Watch latest events from test namespace for CSV - listOpts.ResourceVersion = events.ResourceVersion - w, err := c.KubernetesInterface().CoreV1().Events(testNamespace).Watch(context.Background(), listOpts) - Expect(err).ToNot(HaveOccurred()) - defer w.Stop() - - cleanupCSV, err := createCSV(c, crc, *csv, csv.GetNamespace(), false, false) - Expect(err).ToNot(HaveOccurred()) - defer cleanupCSV() - - By("emitting when requirements are not met") - nextReason := func() string { - if e := <-w.ResultChan(); e.Object != nil { - return e.Object.(*corev1.Event).Reason - } - return "" - } - Eventually(nextReason).Should(Equal("RequirementsNotMet")) - - // Patch the CSV to require an API that we know exists - Eventually(ctx.Ctx().SSAClient().Apply(clientCtx, csv, func(c *operatorsv1alpha1.ClusterServiceVersion) error { - c.Spec.APIServiceDefinitions.Required[0].Group = "packages.operators.coreos.com" - return nil - })).Should(Succeed()) - - By("emitting when requirements are met") - Eventually(nextReason).Should(Equal("AllRequirementsMet")) - }) - - // TODO: test behavior when replaces field doesn't point to existing CSV - It("status invalid CSV", func() { + }) + defer cleanupCRD() + Expect(err).ShouldNot(HaveOccurred()) - // Create CRD - crdPlural := genName("ins") - crdName := crdPlural + ".cluster.com" - cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ - ObjectMeta: metav1.ObjectMeta{ - Name: crdName, - }, - Spec: apiextensions.CustomResourceDefinitionSpec{ - Group: "cluster.com", - Versions: []apiextensions.CustomResourceDefinitionVersion{ + // Create "current" CSV + nginxName := genName("nginx-") + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ { - Name: "v1alpha1", - Served: true, - Storage: true, - Schema: &apiextensions.CustomResourceValidation{ - OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ - Type: "object", - Description: "my crd schema", - }, - }, + Name: genName("dep-"), + Spec: newNginxDeployment(nginxName), }, }, - Names: apiextensions.CustomResourceDefinitionNames{ - Plural: crdPlural, - Singular: crdPlural, - Kind: crdPlural, - ListKind: "list" + crdPlural, - }, - Scope: apiextensions.NamespaceScoped, - }, - }) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCRD() - - // create CSV - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: genName("dep-"), - Spec: newNginxDeployment(genName("nginx-")), - }, - }, - } - - Expect(err).ShouldNot(HaveOccurred()) + } - csv := operatorsv1alpha1.ClusterServiceVersion{ - TypeMeta: metav1.TypeMeta{ - Kind: operatorsv1alpha1.ClusterServiceVersionKind, - APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, - }, - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv"), - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, - }, + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), }, - CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ - Owned: []operatorsv1alpha1.CRDDescription{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, { - Name: crdName, - Version: "apiextensions.k8s.io/v1alpha1", // purposely invalid, should be just v1alpha1 to match CRD - Kind: crdPlural, - DisplayName: crdName, - Description: "In the cluster2", + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, + }, + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "v1alpha1", + Kind: crdPlural, + DisplayName: crdName, + Description: "In the cluster", + }, }, }, }, - }, - } - - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, true, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() - - notServedStatus := operatorsv1alpha1.RequirementStatus{ - Group: "apiextensions.k8s.io", - Version: "v1", - Kind: "CustomResourceDefinition", - Name: crdName, - Status: operatorsv1alpha1.RequirementStatusReasonNotPresent, - Message: "CRD version not served", - } - csvCheckPhaseAndRequirementStatus := func(csv *operatorsv1alpha1.ClusterServiceVersion) bool { - if csv.Status.Phase == operatorsv1alpha1.CSVPhasePending { - for _, status := range csv.Status.RequirementStatus { - if status.Message == notServedStatus.Message { - return true - } - } } - return false - } - - fetchedCSV, err := fetchCSV(crc, csv.Name, testNamespace, csvCheckPhaseAndRequirementStatus) - Expect(err).ShouldNot(HaveOccurred()) - - Expect(fetchedCSV.Status.RequirementStatus).Should(ContainElement(notServedStatus)) - }) - - It("api service resource migrated if adoptable", func() { - depName := genName("hat-server") - mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName("")) - version := "v1alpha1" - mockGroupVersion := strings.Join([]string{mockGroup, version}, "/") - mockKinds := []string{"fedora"} - depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}}) - apiServiceName := strings.Join([]string{version, mockGroup}, ".") + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), true, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - // Create CSVs for the hat-server - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: depName, - Spec: depSpec, - }, - }, - } + // Wait for current CSV to succeed + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds)) - for i, kind := range mockKinds { - owned[i] = operatorsv1alpha1.APIServiceDescription{ - Name: apiServiceName, - Group: mockGroup, - Version: version, - Kind: kind, - DeploymentName: depName, - ContainerPort: int32(5443), - DisplayName: kind, - Description: fmt.Sprintf("A %s", kind), - } - } + // Should have created deployment + dep, err := c.GetDeployment(ns.GetName(), strategy.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(dep).ShouldNot(BeNil()) - csv := operatorsv1alpha1.ClusterServiceVersion{ - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, - }, + // Create "updated" CSV + strategyNew := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + // Same name + Name: strategy.DeploymentSpecs[0].Name, + // Different spec + Spec: newNginxDeployment(nginxName), }, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, - }, - APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ - Owned: owned, - }, - }, - } - csv.SetName("csv-hat-1") - csv.SetNamespace(testNamespace) - - createLegacyAPIResources(&csv, owned[0]) + } - // Create the APIService CSV - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() + // Fetch the current csv + fetchedCSV, err := fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + // Update csv with modified deployment spec + fetchedCSV.Spec.InstallStrategy.StrategySpec = strategyNew - checkLegacyAPIResources(owned[0], true) - }) + Eventually(func() error { + // Update the current csv + _, err = crc.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Update(context.TODO(), fetchedCSV, metav1.UpdateOptions{}) + return err + }).Should(Succeed()) - It("API service resource not migrated if not adoptable", func() { + // Wait for updated CSV to succeed + _, err = fetchCSV(crc, csv.Name, ns.GetName(), func(csv *operatorsv1alpha1.ClusterServiceVersion) bool { - depName := genName("hat-server") - mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName("")) - version := "v1alpha1" - mockGroupVersion := strings.Join([]string{mockGroup, version}, "/") - mockKinds := []string{"fedora"} - depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}}) - apiServiceName := strings.Join([]string{version, mockGroup}, ".") + // Should have updated existing deployment + depUpdated, err := c.GetDeployment(ns.GetName(), strategyNew.DeploymentSpecs[0].Name) + Expect(err).ShouldNot(HaveOccurred()) + Expect(depUpdated).ShouldNot(BeNil()) + // container name has been updated and differs from initial CSV spec and updated CSV spec + Expect(depUpdated.Spec.Template.Spec.Containers[0].Name).ShouldNot(Equal(strategyNew.DeploymentSpecs[0].Spec.Template.Spec.Containers[0].Name)) - // Create CSVs for the hat-server - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: depName, - Spec: depSpec, - }, - }, - } + // Check for success + return csvSucceededChecker(csv) + }) + Expect(err).ShouldNot(HaveOccurred()) - owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds)) - for i, kind := range mockKinds { - owned[i] = operatorsv1alpha1.APIServiceDescription{ - Name: apiServiceName, - Group: mockGroup, - Version: version, - Kind: kind, - DeploymentName: depName, - ContainerPort: int32(5443), - DisplayName: kind, - Description: fmt.Sprintf("A %s", kind), - } - } + }) + It("emits CSV requirement events", func() { - csv := operatorsv1alpha1.ClusterServiceVersion{ - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, + csv := &operatorsv1alpha1.ClusterServiceVersion{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, }, - { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + InstallStrategy: newNginxInstallStrategy(genName("dep-"), nil, nil), + APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ + // Require an API that we know won't exist under our domain + Required: []operatorsv1alpha1.APIServiceDescription{ + { + Group: "bad.packages.operators.coreos.com", + Version: "v1", + Kind: "PackageManifest", + }, + }, }, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, - }, - APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ - Owned: owned, - }, - }, - } - csv.SetName("csv-hat-1") - csv.SetNamespace(testNamespace) - - createLegacyAPIResources(nil, owned[0]) - - // Create the APIService CSV - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() - - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) - - checkLegacyAPIResources(owned[0], false) + } + csv.SetNamespace(ns.GetName()) + csv.SetName(genName("csv-")) - // Cleanup the resources created for this test that were not cleaned up. - deleteLegacyAPIResources(owned[0]) - }) + clientCtx := context.Background() + listOpts := metav1.ListOptions{ + FieldSelector: "involvedObject.kind=ClusterServiceVersion", + } + events, err := c.KubernetesInterface().CoreV1().Events(csv.GetNamespace()).List(clientCtx, listOpts) + Expect(err).ToNot(HaveOccurred()) + + // Watch latest events from test namespace for CSV + listOpts.ResourceVersion = events.ResourceVersion + w, err := c.KubernetesInterface().CoreV1().Events(ns.GetName()).Watch(context.Background(), listOpts) + Expect(err).ToNot(HaveOccurred()) + defer w.Stop() + + cleanupCSV, err := createCSV(c, crc, *csv, csv.GetNamespace(), false, false) + Expect(err).ToNot(HaveOccurred()) + defer cleanupCSV() + + By("emitting when requirements are not met") + nextReason := func() string { + if e := <-w.ResultChan(); e.Object != nil { + return e.Object.(*corev1.Event).Reason + } + return "" + } + Eventually(nextReason).Should(Equal("RequirementsNotMet")) - It("multiple API services on a single pod", func() { - - // Create the deployment that both APIServices will be deployed to. - depName := genName("hat-server") - - // Define the expected mock APIService settings. - version := "v1alpha1" - apiService1Group := fmt.Sprintf("hats.%s.redhat.com", genName("")) - apiService1GroupVersion := strings.Join([]string{apiService1Group, version}, "/") - apiService1Kinds := []string{"fedora"} - apiService1Name := strings.Join([]string{version, apiService1Group}, ".") - - apiService2Group := fmt.Sprintf("hats.%s.redhat.com", genName("")) - apiService2GroupVersion := strings.Join([]string{apiService2Group, version}, "/") - apiService2Kinds := []string{"fez"} - apiService2Name := strings.Join([]string{version, apiService2Group}, ".") - - // Create the deployment spec with the two APIServices. - mockGroupVersionKinds := []mockGroupVersionKind{ - { - depName, - apiService1GroupVersion, - apiService1Kinds, - 5443, - }, - { - depName, - apiService2GroupVersion, - apiService2Kinds, - 5444, - }, - } - depSpec := newMockExtServerDeployment(depName, mockGroupVersionKinds) + // Patch the CSV to require an API that we know exists + Eventually(ctx.Ctx().SSAClient().Apply(clientCtx, csv, func(c *operatorsv1alpha1.ClusterServiceVersion) error { + c.Spec.APIServiceDefinitions.Required[0].Group = "packages.operators.coreos.com" + return nil + })).Should(Succeed()) - // Create the CSV. - strategy := operatorsv1alpha1.StrategyDetailsDeployment{ - DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ - { - Name: depName, - Spec: depSpec, - }, - }, - } + By("emitting when requirements are met") + Eventually(nextReason).Should(Equal("AllRequirementsMet")) + }) - // Update the owned APIServices two include the two APIServices. - owned := []operatorsv1alpha1.APIServiceDescription{ - { - Name: apiService1Name, - Group: apiService1Group, - Version: version, - Kind: apiService1Kinds[0], - DeploymentName: depName, - ContainerPort: int32(5443), - DisplayName: apiService1Kinds[0], - Description: fmt.Sprintf("A %s", apiService1Kinds[0]), - }, - { - Name: apiService2Name, - Group: apiService2Group, - Version: version, - Kind: apiService2Kinds[0], - DeploymentName: depName, - ContainerPort: int32(5444), - DisplayName: apiService2Kinds[0], - Description: fmt.Sprintf("A %s", apiService2Kinds[0]), - }, - } + // TODO: test behavior when replaces field doesn't point to existing CSV + It("status invalid CSV", func() { - csv := operatorsv1alpha1.ClusterServiceVersion{ - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - MinKubeVersion: "0.0.0", - InstallModes: []operatorsv1alpha1.InstallMode{ - { - Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, - Supported: true, - }, - { - Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, - Supported: true, + // Create CRD + crdPlural := genName("ins") + crdName := crdPlural + ".cluster.com" + cleanupCRD, err := createCRD(c, apiextensions.CustomResourceDefinition{ + ObjectMeta: metav1.ObjectMeta{ + Name: crdName, + }, + Spec: apiextensions.CustomResourceDefinitionSpec{ + Group: "cluster.com", + Versions: []apiextensions.CustomResourceDefinitionVersion{ + { + Name: "v1alpha1", + Served: true, + Storage: true, + Schema: &apiextensions.CustomResourceValidation{ + OpenAPIV3Schema: &apiextensions.JSONSchemaProps{ + Type: "object", + Description: "my crd schema", + }, + }, + }, }, - { - Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, - Supported: true, + Names: apiextensions.CustomResourceDefinitionNames{ + Plural: crdPlural, + Singular: crdPlural, + Kind: crdPlural, + ListKind: "list" + crdPlural, }, + Scope: apiextensions.NamespaceScoped, + }, + }) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCRD() + + // create CSV + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + Name: genName("dep-"), + Spec: newNginxDeployment(genName("nginx-")), }, }, - InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ - StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, - StrategySpec: strategy, + } + Expect(err).ShouldNot(HaveOccurred()) + + csv := operatorsv1alpha1.ClusterServiceVersion{ + TypeMeta: metav1.TypeMeta{ + Kind: operatorsv1alpha1.ClusterServiceVersionKind, + APIVersion: operatorsv1alpha1.ClusterServiceVersionAPIVersion, }, - APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ - Owned: owned, + ObjectMeta: metav1.ObjectMeta{ + Name: genName("csv"), }, - }, - } - csv.SetName("csv-hat-1") - csv.SetNamespace(testNamespace) - - // Create the APIService CSV - cleanupCSV, err := createCSV(c, crc, csv, testNamespace, false, false) - Expect(err).ShouldNot(HaveOccurred()) - defer cleanupCSV() - - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) - Expect(err).ShouldNot(HaveOccurred()) + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, + }, + CustomResourceDefinitions: operatorsv1alpha1.CustomResourceDefinitions{ + Owned: []operatorsv1alpha1.CRDDescription{ + { + Name: crdName, + Version: "apiextensions.k8s.io/v1alpha1", // purposely invalid, should be just v1alpha1 to match CRD + Kind: crdPlural, + DisplayName: crdName, + Description: "In the cluster2", + }, + }, + }, + }, + } - // Check that the APIService caBundles are equal - apiService1, err := c.GetAPIService(apiService1Name) - Expect(err).ShouldNot(HaveOccurred()) + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), true, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() + + notServedStatus := operatorsv1alpha1.RequirementStatus{ + Group: "apiextensions.k8s.io", + Version: "v1", + Kind: "CustomResourceDefinition", + Name: crdName, + Status: operatorsv1alpha1.RequirementStatusReasonNotPresent, + Message: "CRD version not served", + } + csvCheckPhaseAndRequirementStatus := func(csv *operatorsv1alpha1.ClusterServiceVersion) bool { + if csv.Status.Phase == operatorsv1alpha1.CSVPhasePending { + for _, status := range csv.Status.RequirementStatus { + if status.Message == notServedStatus.Message { + return true + } + } + } + return false + } - apiService2, err := c.GetAPIService(apiService2Name) - Expect(err).ShouldNot(HaveOccurred()) + fetchedCSV, err := fetchCSV(crc, csv.Name, ns.GetName(), csvCheckPhaseAndRequirementStatus) + Expect(err).ShouldNot(HaveOccurred()) - Expect(apiService2.Spec.CABundle).Should(Equal(apiService1.Spec.CABundle)) - }) -}) + Expect(fetchedCSV.Status.RequirementStatus).Should(ContainElement(notServedStatus)) + }) -var _ = Describe("Disabling copied CSVs", func() { - var ( - ns corev1.Namespace - csv operatorsv1alpha1.ClusterServiceVersion - ) + It("api service resource migrated if adoptable", func() { - BeforeEach(func() { - nsname := genName("csv-toggle-test-") - og := operatorsv1.OperatorGroup{ - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-operatorgroup", nsname), - Namespace: nsname, - }, - } - ns = SetupGeneratedTestNamespaceWithOperatorGroup(nsname, og) + depName := genName("hat-server") + mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName("")) + version := "v1alpha1" + mockGroupVersion := strings.Join([]string{mockGroup, version}, "/") + mockKinds := []string{"fedora"} + depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}}) + apiServiceName := strings.Join([]string{version, mockGroup}, ".") - csv = operatorsv1alpha1.ClusterServiceVersion{ - ObjectMeta: metav1.ObjectMeta{ - Name: genName("csv-toggle-test-"), - Namespace: nsname, - }, - Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ - InstallStrategy: newNginxInstallStrategy(genName("csv-toggle-test-"), nil, nil), - InstallModes: []operatorsv1alpha1.InstallMode{ + // Create CSVs for the hat-server + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ { - Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, - Supported: true, + Name: depName, + Spec: depSpec, }, }, - }, - } - err := ctx.Ctx().Client().Create(context.Background(), &csv) - Expect(err).ShouldNot(HaveOccurred()) - }) - AfterEach(func() { - Eventually(func() error { - err := ctx.Ctx().Client().Delete(context.Background(), &csv) - if err != nil && k8serrors.IsNotFound(err) { - return err } - return nil - }).Should(Succeed()) - TeardownNamespace(ns.GetName()) - Eventually(func() error { - var namespace corev1.Namespace - return ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&ns), &namespace) - }).Should(WithTransform(k8serrors.IsNotFound, BeTrue())) - }) - - When("an operator is installed in AllNamespace mode", func() { - // issue: https://github.com/operator-framework/operator-lifecycle-manager/issues/2643 - It("[FLAKE] should have Copied CSVs in all other namespaces", func() { - Eventually(func() error { - requirement, err := k8slabels.NewRequirement(operatorsv1alpha1.CopiedLabelKey, selection.Equals, []string{csv.GetNamespace()}) - if err != nil { - return err + owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds)) + for i, kind := range mockKinds { + owned[i] = operatorsv1alpha1.APIServiceDescription{ + Name: apiServiceName, + Group: mockGroup, + Version: version, + Kind: kind, + DeploymentName: depName, + ContainerPort: int32(5443), + DisplayName: kind, + Description: fmt.Sprintf("A %s", kind), } + } - var copiedCSVs operatorsv1alpha1.ClusterServiceVersionList - err = ctx.Ctx().Client().List(context.TODO(), &copiedCSVs, &client.ListOptions{ - LabelSelector: k8slabels.NewSelector().Add(*requirement), - }) - if err != nil { - return err - } + csv := operatorsv1alpha1.ClusterServiceVersion{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, + }, + APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ + Owned: owned, + }, + }, + } + csv.SetName("csv-hat-1") + csv.SetNamespace(ns.GetName()) - var namespaces corev1.NamespaceList - if err := ctx.Ctx().Client().List(context.TODO(), &namespaces, &client.ListOptions{}); err != nil { - return err - } + createLegacyAPIResources(ns.GetName(), &csv, owned[0]) - if len(namespaces.Items)-1 != len(copiedCSVs.Items) { - return fmt.Errorf("%d copied CSVs found, expected %d", len(copiedCSVs.Items), len(namespaces.Items)-1) - } + // Create the APIService CSV + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - return nil - }).Should(Succeed()) + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) + + checkLegacyAPIResources(ns.GetName(), owned[0], true) }) - }) - When("Copied CSVs are disabled", func() { - BeforeEach(func() { - Eventually(func() error { - var olmConfig operatorsv1.OLMConfig - if err := ctx.Ctx().Client().Get(context.TODO(), apitypes.NamespacedName{Name: "cluster"}, &olmConfig); err != nil { - ctx.Ctx().Logf("Error getting olmConfig %v", err) - return err - } + It("API service resource not migrated if not adoptable", func() { - // Exit early if copied CSVs are disabled. - if !olmConfig.CopiedCSVsAreEnabled() { - return nil - } + depName := genName("hat-server") + mockGroup := fmt.Sprintf("hats.%s.redhat.com", genName("")) + version := "v1alpha1" + mockGroupVersion := strings.Join([]string{mockGroup, version}, "/") + mockKinds := []string{"fedora"} + depSpec := newMockExtServerDeployment(depName, []mockGroupVersionKind{{depName, mockGroupVersion, mockKinds, 5443}}) + apiServiceName := strings.Join([]string{version, mockGroup}, ".") - olmConfig.Spec = operatorsv1.OLMConfigSpec{ - Features: &operatorsv1.Features{ - DisableCopiedCSVs: getPointer(true), + // Create CSVs for the hat-server + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ + { + Name: depName, + Spec: depSpec, }, - } - - if err := ctx.Ctx().Client().Update(context.TODO(), &olmConfig); err != nil { - ctx.Ctx().Logf("Error setting olmConfig %v", err) - return err - } - - return nil - }).Should(Succeed()) - }) - - It("should not have any copied CSVs", func() { - Eventually(func() error { - requirement, err := k8slabels.NewRequirement(operatorsv1alpha1.CopiedLabelKey, selection.Equals, []string{csv.GetNamespace()}) - if err != nil { - return err - } + }, + } - var copiedCSVs operatorsv1alpha1.ClusterServiceVersionList - err = ctx.Ctx().Client().List(context.TODO(), &copiedCSVs, &client.ListOptions{ - LabelSelector: k8slabels.NewSelector().Add(*requirement), - }) - if err != nil { - return err + owned := make([]operatorsv1alpha1.APIServiceDescription, len(mockKinds)) + for i, kind := range mockKinds { + owned[i] = operatorsv1alpha1.APIServiceDescription{ + Name: apiServiceName, + Group: mockGroup, + Version: version, + Kind: kind, + DeploymentName: depName, + ContainerPort: int32(5443), + DisplayName: kind, + Description: fmt.Sprintf("A %s", kind), } + } - if numCSVs := len(copiedCSVs.Items); numCSVs != 0 { - return fmt.Errorf("Found %d copied CSVs, should be 0", numCSVs) - } - return nil - }).Should(Succeed()) - }) + csv := operatorsv1alpha1.ClusterServiceVersion{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, + }, + APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ + Owned: owned, + }, + }, + } + csv.SetName("csv-hat-1") + csv.SetNamespace(ns.GetName()) - // issue: https://github.com/operator-framework/operator-lifecycle-manager/issues/2634 - It("[FLAKE] should be reflected in the olmConfig.Status.Condition array that the expected number of copied CSVs exist", func() { - Eventually(func() error { - var olmConfig operatorsv1.OLMConfig - if err := ctx.Ctx().Client().Get(context.TODO(), apitypes.NamespacedName{Name: "cluster"}, &olmConfig); err != nil { - return err - } + createLegacyAPIResources(ns.GetName(), nil, owned[0]) - foundCondition := meta.FindStatusCondition(olmConfig.Status.Conditions, operatorsv1.DisabledCopiedCSVsConditionType) - if foundCondition == nil { - return fmt.Errorf("%s condition not found", operatorsv1.DisabledCopiedCSVsConditionType) - } + // Create the APIService CSV + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - expectedCondition := metav1.Condition{ - Reason: "NoCopiedCSVsFound", - Message: "Copied CSVs are disabled and none were found for operators installed in AllNamespace mode", - Status: metav1.ConditionTrue, - } + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - if foundCondition.Reason != expectedCondition.Reason || - foundCondition.Message != expectedCondition.Message || - foundCondition.Status != expectedCondition.Status { - return fmt.Errorf("condition does not have expected reason, message, and status. Expected %v, got %v", expectedCondition, foundCondition) - } + checkLegacyAPIResources(ns.GetName(), owned[0], false) - return nil - }).Should(Succeed()) + // Cleanup the resources created for this test that were not cleaned up. + deleteLegacyAPIResources(ns.GetName(), owned[0]) }) - }) - When("Copied CSVs are toggled back on", func() { - BeforeEach(func() { - Eventually(func() error { - var olmConfig operatorsv1.OLMConfig - if err := ctx.Ctx().Client().Get(context.TODO(), apitypes.NamespacedName{Name: "cluster"}, &olmConfig); err != nil { - return err - } + It("multiple API services on a single pod", func() { - // Exit early if copied CSVs are enabled. - if olmConfig.CopiedCSVsAreEnabled() { - return nil - } + // Create the deployment that both APIServices will be deployed to. + depName := genName("hat-server") - olmConfig.Spec = operatorsv1.OLMConfigSpec{ - Features: &operatorsv1.Features{ - DisableCopiedCSVs: getPointer(false), - }, - } + // Define the expected mock APIService settings. + version := "v1alpha1" + apiService1Group := fmt.Sprintf("hats.%s.redhat.com", genName("")) + apiService1GroupVersion := strings.Join([]string{apiService1Group, version}, "/") + apiService1Kinds := []string{"fedora"} + apiService1Name := strings.Join([]string{version, apiService1Group}, ".") - if err := ctx.Ctx().Client().Update(context.TODO(), &olmConfig); err != nil { - return err - } + apiService2Group := fmt.Sprintf("hats.%s.redhat.com", genName("")) + apiService2GroupVersion := strings.Join([]string{apiService2Group, version}, "/") + apiService2Kinds := []string{"fez"} + apiService2Name := strings.Join([]string{version, apiService2Group}, ".") - return nil - }).Should(Succeed()) - }) + // Create the deployment spec with the two APIServices. + mockGroupVersionKinds := []mockGroupVersionKind{ + { + depName, + apiService1GroupVersion, + apiService1Kinds, + 5443, + }, + { + depName, + apiService2GroupVersion, + apiService2Kinds, + 5444, + }, + } + depSpec := newMockExtServerDeployment(depName, mockGroupVersionKinds) - // issue: https://github.com/operator-framework/operator-lifecycle-manager/issues/2634 - It("[FLAKE] should have copied CSVs in all other Namespaces", func() { - Eventually(func() error { - // find copied csvs... - requirement, err := k8slabels.NewRequirement(operatorsv1alpha1.CopiedLabelKey, selection.Equals, []string{csv.GetNamespace()}) - if err != nil { - return err - } + // Create the CSV. + strategy := operatorsv1alpha1.StrategyDetailsDeployment{ + DeploymentSpecs: []operatorsv1alpha1.StrategyDeploymentSpec{ + { + Name: depName, + Spec: depSpec, + }, + }, + } - var copiedCSVs operatorsv1alpha1.ClusterServiceVersionList - err = ctx.Ctx().Client().List(context.TODO(), &copiedCSVs, &client.ListOptions{ - LabelSelector: k8slabels.NewSelector().Add(*requirement), - }) - if err != nil { - return err - } + // Update the owned APIServices two include the two APIServices. + owned := []operatorsv1alpha1.APIServiceDescription{ + { + Name: apiService1Name, + Group: apiService1Group, + Version: version, + Kind: apiService1Kinds[0], + DeploymentName: depName, + ContainerPort: int32(5443), + DisplayName: apiService1Kinds[0], + Description: fmt.Sprintf("A %s", apiService1Kinds[0]), + }, + { + Name: apiService2Name, + Group: apiService2Group, + Version: version, + Kind: apiService2Kinds[0], + DeploymentName: depName, + ContainerPort: int32(5444), + DisplayName: apiService2Kinds[0], + Description: fmt.Sprintf("A %s", apiService2Kinds[0]), + }, + } - var namespaces corev1.NamespaceList - if err := ctx.Ctx().Client().List(context.TODO(), &namespaces, &client.ListOptions{FieldSelector: fields.SelectorFromSet(map[string]string{"status.phase": "Active"})}); err != nil { - return err - } + csv := operatorsv1alpha1.ClusterServiceVersion{ + Spec: operatorsv1alpha1.ClusterServiceVersionSpec{ + MinKubeVersion: "0.0.0", + InstallModes: []operatorsv1alpha1.InstallMode{ + { + Type: operatorsv1alpha1.InstallModeTypeOwnNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeSingleNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeMultiNamespace, + Supported: true, + }, + { + Type: operatorsv1alpha1.InstallModeTypeAllNamespaces, + Supported: true, + }, + }, + InstallStrategy: operatorsv1alpha1.NamedInstallStrategy{ + StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, + StrategySpec: strategy, + }, + APIServiceDefinitions: operatorsv1alpha1.APIServiceDefinitions{ + Owned: owned, + }, + }, + } + csv.SetName("csv-hat-1") + csv.SetNamespace(ns.GetName()) - targetNamespaces := len(namespaces.Items) - 1 - for _, ns := range namespaces.Items { - // filter out any namespaces that are currently reporting a Terminating phase - // as the API server will reject any resource events in terminating namespaces. - if ns.Status.Phase == "Terminating" { - targetNamespaces-- - } - } - if targetNamespaces != len(copiedCSVs.Items) { - return fmt.Errorf("%d copied CSVs found, expected %d", len(copiedCSVs.Items), targetNamespaces) - } - return nil - }).Should(Succeed()) - }) + // Create the APIService CSV + cleanupCSV, err := createCSV(c, crc, csv, ns.GetName(), false, false) + Expect(err).ShouldNot(HaveOccurred()) + defer cleanupCSV() - // issue: https://github.com/operator-framework/operator-lifecycle-manager/issues/2641 - It("[FLAKE] should be reflected in the olmConfig.Status.Condition array that the expected number of copied CSVs exist", func() { - Eventually(func() error { - var olmConfig operatorsv1.OLMConfig - if err := ctx.Ctx().Client().Get(context.TODO(), apitypes.NamespacedName{Name: "cluster"}, &olmConfig); err != nil { - return err - } - foundCondition := meta.FindStatusCondition(olmConfig.Status.Conditions, operatorsv1.DisabledCopiedCSVsConditionType) - if foundCondition == nil { - return fmt.Errorf("%s condition not found", operatorsv1.DisabledCopiedCSVsConditionType) - } + _, err = fetchCSV(crc, csv.Name, ns.GetName(), csvSucceededChecker) + Expect(err).ShouldNot(HaveOccurred()) - expectedCondition := metav1.Condition{ - Reason: "CopiedCSVsEnabled", - Message: "Copied CSVs are enabled and present across the cluster", - Status: metav1.ConditionFalse, - } + // Check that the APIService caBundles are equal + apiService1, err := c.GetAPIService(apiService1Name) + Expect(err).ShouldNot(HaveOccurred()) - if foundCondition.Reason != expectedCondition.Reason || - foundCondition.Message != expectedCondition.Message || - foundCondition.Status != expectedCondition.Status { - return fmt.Errorf("condition does not have expected reason, message, and status. Expected %v, got %v", expectedCondition, foundCondition) - } + apiService2, err := c.GetAPIService(apiService2Name) + Expect(err).ShouldNot(HaveOccurred()) - return nil - }).Should(Succeed()) + Expect(apiService2.Spec.CABundle).Should(Equal(apiService1.Spec.CABundle)) }) }) }) @@ -4730,7 +4453,7 @@ func awaitCSV(c versioned.Interface, namespace, name string, checker csvConditio Eventually(func() (bool, error) { fetched, err = c.OperatorsV1alpha1().ClusterServiceVersions(namespace).Get(context.TODO(), name, metav1.GetOptions{}) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return false, nil } return false, err @@ -4745,11 +4468,11 @@ func awaitCSV(c versioned.Interface, namespace, name string, checker csvConditio return fetched, err } -func waitForDeployment(c operatorclient.ClientInterface, name string) error { +func waitForDeployment(namespace string, c operatorclient.ClientInterface, name string) error { return wait.Poll(pollInterval, pollDuration, func() (bool, error) { - _, err := c.GetDeployment(testNamespace, name) + _, err := c.GetDeployment(namespace, name) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return false, nil } return false, err @@ -4758,13 +4481,13 @@ func waitForDeployment(c operatorclient.ClientInterface, name string) error { }) } -func waitForDeploymentToDelete(c operatorclient.ClientInterface, name string) error { +func waitForDeploymentToDelete(namespace string, c operatorclient.ClientInterface, name string) error { var err error Eventually(func() (bool, error) { ctx.Ctx().Logf("waiting for deployment %s to delete", name) - _, err := c.GetDeployment(testNamespace, name) - if k8serrors.IsNotFound(err) { + _, err := c.GetDeployment(namespace, name) + if apierrors.IsNotFound(err) { ctx.Ctx().Logf("deleted %s", name) return true, nil } @@ -4777,9 +4500,9 @@ func waitForDeploymentToDelete(c operatorclient.ClientInterface, name string) er return err } -func csvExists(c versioned.Interface, name string) bool { - fetched, err := c.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Get(context.TODO(), name, metav1.GetOptions{}) - if k8serrors.IsNotFound(err) { +func csvExists(namespace string, c versioned.Interface, name string) bool { + fetched, err := c.OperatorsV1alpha1().ClusterServiceVersions(namespace).Get(context.TODO(), name, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { return false } ctx.Ctx().Logf("%s (%s): %s", fetched.Status.Phase, fetched.Status.Reason, fetched.Status.Message) @@ -4789,21 +4512,21 @@ func csvExists(c versioned.Interface, name string) bool { return true } -func deleteLegacyAPIResources(desc operatorsv1alpha1.APIServiceDescription) { +func deleteLegacyAPIResources(namespace string, desc operatorsv1alpha1.APIServiceDescription) { c := newKubeClient() apiServiceName := fmt.Sprintf("%s.%s", desc.Version, desc.Group) - err := c.DeleteService(testNamespace, strings.Replace(apiServiceName, ".", "-", -1), &metav1.DeleteOptions{}) + err := c.DeleteService(namespace, strings.Replace(apiServiceName, ".", "-", -1), &metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) - err = c.DeleteSecret(testNamespace, apiServiceName+"-cert", &metav1.DeleteOptions{}) + err = c.DeleteSecret(namespace, apiServiceName+"-cert", &metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) - err = c.DeleteRole(testNamespace, apiServiceName+"-cert", &metav1.DeleteOptions{}) + err = c.DeleteRole(namespace, apiServiceName+"-cert", &metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) - err = c.DeleteRoleBinding(testNamespace, apiServiceName+"-cert", &metav1.DeleteOptions{}) + err = c.DeleteRoleBinding(namespace, apiServiceName+"-cert", &metav1.DeleteOptions{}) Expect(err).ShouldNot(HaveOccurred()) err = c.DeleteClusterRoleBinding(apiServiceName+"-system:auth-delegator", &metav1.DeleteOptions{}) @@ -4813,7 +4536,7 @@ func deleteLegacyAPIResources(desc operatorsv1alpha1.APIServiceDescription) { Expect(err).ShouldNot(HaveOccurred()) } -func createLegacyAPIResources(csv *operatorsv1alpha1.ClusterServiceVersion, desc operatorsv1alpha1.APIServiceDescription) { +func createLegacyAPIResources(namespace string, csv *operatorsv1alpha1.ClusterServiceVersion, desc operatorsv1alpha1.APIServiceDescription) { c := newKubeClient() apiServiceName := fmt.Sprintf("%s.%s", desc.Version, desc.Group) @@ -4821,7 +4544,7 @@ func createLegacyAPIResources(csv *operatorsv1alpha1.ClusterServiceVersion, desc // Attempt to create the legacy service service := corev1.Service{} service.SetName(strings.Replace(apiServiceName, ".", "-", -1)) - service.SetNamespace(testNamespace) + service.SetNamespace(namespace) if csv != nil { err := ownerutil.AddOwnerLabels(&service, csv) Expect(err).ShouldNot(HaveOccurred()) @@ -4834,21 +4557,21 @@ func createLegacyAPIResources(csv *operatorsv1alpha1.ClusterServiceVersion, desc // Attempt to create the legacy secret secret := corev1.Secret{} secret.SetName(apiServiceName + "-cert") - secret.SetNamespace(testNamespace) + secret.SetNamespace(namespace) if csv != nil { err = ownerutil.AddOwnerLabels(&secret, csv) Expect(err).ShouldNot(HaveOccurred()) } _, err = c.CreateSecret(&secret) - if err != nil && !k8serrors.IsAlreadyExists(err) { + if err != nil && !apierrors.IsAlreadyExists(err) { Expect(err).ShouldNot(HaveOccurred()) } // Attempt to create the legacy secret role role := rbacv1.Role{} role.SetName(apiServiceName + "-cert") - role.SetNamespace(testNamespace) + role.SetNamespace(namespace) if csv != nil { err = ownerutil.AddOwnerLabels(&role, csv) Expect(err).ShouldNot(HaveOccurred()) @@ -4859,7 +4582,7 @@ func createLegacyAPIResources(csv *operatorsv1alpha1.ClusterServiceVersion, desc // Attempt to create the legacy secret role binding roleBinding := rbacv1.RoleBinding{} roleBinding.SetName(apiServiceName + "-cert") - roleBinding.SetNamespace(testNamespace) + roleBinding.SetNamespace(namespace) roleBinding.RoleRef = rbacv1.RoleRef{ APIGroup: "rbac.authorization.k8s.io", Kind: "Role", @@ -4900,31 +4623,31 @@ func createLegacyAPIResources(csv *operatorsv1alpha1.ClusterServiceVersion, desc Expect(err).ShouldNot(HaveOccurred()) } -func checkLegacyAPIResources(desc operatorsv1alpha1.APIServiceDescription, expectedIsNotFound bool) { +func checkLegacyAPIResources(namespace string, desc operatorsv1alpha1.APIServiceDescription, expectedIsNotFound bool) { c := newKubeClient() apiServiceName := fmt.Sprintf("%s.%s", desc.Version, desc.Group) // Attempt to create the legacy service - _, err := c.GetService(testNamespace, strings.Replace(apiServiceName, ".", "-", -1)) - Expect(k8serrors.IsNotFound(err)).Should(Equal(expectedIsNotFound)) + _, err := c.GetService(namespace, strings.Replace(apiServiceName, ".", "-", -1)) + Expect(apierrors.IsNotFound(err)).Should(Equal(expectedIsNotFound)) // Attempt to create the legacy secret - _, err = c.GetSecret(testNamespace, apiServiceName+"-cert") - Expect(k8serrors.IsNotFound(err)).Should(Equal(expectedIsNotFound)) + _, err = c.GetSecret(namespace, apiServiceName+"-cert") + Expect(apierrors.IsNotFound(err)).Should(Equal(expectedIsNotFound)) // Attempt to create the legacy secret role - _, err = c.GetRole(testNamespace, apiServiceName+"-cert") - Expect(k8serrors.IsNotFound(err)).Should(Equal(expectedIsNotFound)) + _, err = c.GetRole(namespace, apiServiceName+"-cert") + Expect(apierrors.IsNotFound(err)).Should(Equal(expectedIsNotFound)) // Attempt to create the legacy secret role binding - _, err = c.GetRoleBinding(testNamespace, apiServiceName+"-cert") - Expect(k8serrors.IsNotFound(err)).Should(Equal(expectedIsNotFound)) + _, err = c.GetRoleBinding(namespace, apiServiceName+"-cert") + Expect(apierrors.IsNotFound(err)).Should(Equal(expectedIsNotFound)) // Attempt to create the legacy authDelegatorClusterRoleBinding _, err = c.GetClusterRoleBinding(apiServiceName + "-system:auth-delegator") - Expect(k8serrors.IsNotFound(err)).Should(Equal(expectedIsNotFound)) + Expect(apierrors.IsNotFound(err)).Should(Equal(expectedIsNotFound)) // Attempt to create the legacy authReadingRoleBinding _, err = c.GetRoleBinding("kube-system", apiServiceName+"-auth-reader") - Expect(k8serrors.IsNotFound(err)).Should(Equal(expectedIsNotFound)) + Expect(apierrors.IsNotFound(err)).Should(Equal(expectedIsNotFound)) } diff --git a/staging/operator-lifecycle-manager/test/e2e/ctx/ctx.go b/staging/operator-lifecycle-manager/test/e2e/ctx/ctx.go index cf1154a196..56688c2d6f 100644 --- a/staging/operator-lifecycle-manager/test/e2e/ctx/ctx.go +++ b/staging/operator-lifecycle-manager/test/e2e/ctx/ctx.go @@ -8,6 +8,7 @@ import ( "strings" g "github.com/onsi/ginkgo" + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/dynamic" @@ -36,8 +37,9 @@ type TestContext struct { packageClient pversioned.Interface ssaClient *controllerclient.ServerSideApplier - kubeconfigPath string - artifactsDir string + kubeconfigPath string + artifactsDir string + artifactsScriptPath string scheme *runtime.Scheme @@ -115,8 +117,7 @@ func (ctx TestContext) DumpNamespaceArtifacts(namespace string) error { "KUBECONFIG=" + kubeconfigPath, } - // compiled test binary running e2e tests is run from the root ./bin directory - cmd := exec.Command("../test/e2e/collect-ci-artifacts.sh") + cmd := exec.Command(ctx.artifactsScriptPath) cmd.Env = append(cmd.Env, envvars...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr @@ -136,6 +137,17 @@ func setDerivedFields(ctx *TestContext) error { return fmt.Errorf("nil RESTClient") } + if ctx.artifactsDir == "" { + if artifactsDir := os.Getenv("ARTIFACTS_DIR"); artifactsDir != "" { + ctx.artifactsDir = artifactsDir + } + } + if ctx.artifactsScriptPath == "" { + if scriptPath := os.Getenv("E2E_ARTIFACTS_SCRIPT"); scriptPath != "" { + ctx.artifactsScriptPath = scriptPath + } + } + kubeClient, err := operatorclient.NewClientFromRestConfig(ctx.restConfig) if err != nil { return err @@ -162,12 +174,12 @@ func setDerivedFields(ctx *TestContext) error { ctx.scheme = runtime.NewScheme() localSchemeBuilder := runtime.NewSchemeBuilder( - apiextensionsv1.AddToScheme, kscheme.AddToScheme, operatorsv1alpha1.AddToScheme, operatorsv1.AddToScheme, operatorsv2.AddToScheme, apiextensionsv1.AddToScheme, + apiextensions.AddToScheme, ) if err := localSchemeBuilder.AddToScheme(ctx.scheme); err != nil { return err diff --git a/staging/operator-lifecycle-manager/test/e2e/ctx/provisioner_kind.go b/staging/operator-lifecycle-manager/test/e2e/ctx/provisioner_kind.go index f9f7971ffc..27f6d7c78c 100644 --- a/staging/operator-lifecycle-manager/test/e2e/ctx/provisioner_kind.go +++ b/staging/operator-lifecycle-manager/test/e2e/ctx/provisioner_kind.go @@ -1,3 +1,4 @@ +//go:build kind // +build kind package ctx @@ -135,10 +136,6 @@ func Provision(ctx *TestContext) (func(), error) { return nil, fmt.Errorf("error loading kubeconfig: %s", err.Error()) } ctx.restConfig = restConfig - - if artifactsDir := os.Getenv("ARTIFACTS_DIR"); artifactsDir != "" { - ctx.artifactsDir = artifactsDir - } ctx.kubeconfigPath = kubeconfigPath var once sync.Once diff --git a/staging/operator-lifecycle-manager/test/e2e/deprecated_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/deprecated_e2e_test.go index cadb2489b7..dcfcaff6a9 100644 --- a/staging/operator-lifecycle-manager/test/e2e/deprecated_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/deprecated_e2e_test.go @@ -2,89 +2,92 @@ package e2e import ( "context" + "fmt" "time" "github.com/blang/semver/v4" . "github.com/onsi/ginkgo" - "github.com/onsi/ginkgo/extensions/table" . "github.com/onsi/gomega" + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" operatorsv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1" + "github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx" ) var missingAPI = `{"apiVersion":"verticalpodautoscalers.autoscaling.k8s.io/v1","kind":"VerticalPodAutoscaler","metadata":{"name":"my.thing","namespace":"foo"}}` var _ = Describe("Not found APIs", func() { + + var ns corev1.Namespace + BeforeEach(func() { - csv := newCSV("test-csv", testNamespace, "", semver.Version{}, nil, nil, nil) + namespaceName := genName("deprecated-e2e-") + og := operatorsv1.OperatorGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-operatorgroup", namespaceName), + Namespace: namespaceName, + }, + } + ns = SetupGeneratedTestNamespaceWithOperatorGroup(namespaceName, og) + + csv := newCSV("test-csv", ns.GetName(), "", semver.Version{}, nil, nil, nil) Expect(ctx.Ctx().Client().Create(context.TODO(), &csv)).To(Succeed()) }) + AfterEach(func() { - TearDown(testNamespace) + TeardownNamespace(ns.GetName()) }) - When("objects with APIs that are not on-cluster are created in the installplan", func() { - // each entry is an installplan with a deprecated resource - type payload struct { - name string - IP *operatorsv1alpha1.InstallPlan - errMessage string - } - - tableEntries := []table.TableEntry{ - table.Entry("contains an entry with a missing API not found on cluster ", payload{ - name: "installplan contains a missing API", - IP: &operatorsv1alpha1.InstallPlan{ + Context("objects with APIs that are not on-cluster are created in the installplan", func() { + When("installplan contains a missing API", func() { + It("the ip enters a failed state with a helpful error message", func() { + ip := &operatorsv1alpha1.InstallPlan{ ObjectMeta: metav1.ObjectMeta{ - Namespace: *namespace, // this is necessary due to ginkgo table semantics, see https://github.com/onsi/ginkgo/issues/378 Name: "test-plan-api", + Namespace: ns.GetName(), }, Spec: operatorsv1alpha1.InstallPlanSpec{ Approval: operatorsv1alpha1.ApprovalAutomatic, Approved: true, ClusterServiceVersionNames: []string{}, }, - }, - errMessage: "api-server resource not found installing VerticalPodAutoscaler my.thing: GroupVersionKind " + - "verticalpodautoscalers.autoscaling.k8s.io/v1, Kind=VerticalPodAutoscaler not found on the cluster", - }), - } - - table.DescribeTable("the ip enters a failed state with a helpful error message", func(tt payload) { - Expect(ctx.Ctx().Client().Create(context.Background(), tt.IP)).To(Succeed()) + } + Expect(ctx.Ctx().Client().Create(context.Background(), ip)).To(Succeed()) - tt.IP.Status = operatorsv1alpha1.InstallPlanStatus{ - Phase: operatorsv1alpha1.InstallPlanPhaseInstalling, - CatalogSources: []string{}, - Plan: []*operatorsv1alpha1.Step{ - { - Resolving: "test-csv", - Status: operatorsv1alpha1.StepStatusUnknown, - Resource: operatorsv1alpha1.StepResource{ - Name: "my.thing", - Group: "verticalpodautoscalers.autoscaling.k8s.io", - Version: "v1", - Kind: "VerticalPodAutoscaler", - Manifest: missingAPI, + ip.Status = operatorsv1alpha1.InstallPlanStatus{ + Phase: operatorsv1alpha1.InstallPlanPhaseInstalling, + CatalogSources: []string{}, + Plan: []*operatorsv1alpha1.Step{ + { + Resolving: "test-csv", + Status: operatorsv1alpha1.StepStatusUnknown, + Resource: operatorsv1alpha1.StepResource{ + Name: "my.thing", + Group: "verticalpodautoscalers.autoscaling.k8s.io", + Version: "v1", + Kind: "VerticalPodAutoscaler", + Manifest: missingAPI, + }, }, }, - }, - } + } - Expect(ctx.Ctx().Client().Status().Update(context.Background(), tt.IP)).To(Succeed(), "failed to update the resource") + Expect(ctx.Ctx().Client().Status().Update(context.Background(), ip)).To(Succeed(), "failed to update the resource") - // The IP sits in the Installing phase with the GVK missing error - Eventually(func() (*operatorsv1alpha1.InstallPlan, error) { - return tt.IP, ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(tt.IP), tt.IP) - }).Should(And(HavePhase(operatorsv1alpha1.InstallPlanPhaseInstalling)), HaveMessage(tt.errMessage)) + errMessage := "api-server resource not found installing VerticalPodAutoscaler my.thing: GroupVersionKind " + + "verticalpodautoscalers.autoscaling.k8s.io/v1, Kind=VerticalPodAutoscaler not found on the cluster" + // The IP sits in the Installing phase with the GVK missing error + Eventually(func() (*operatorsv1alpha1.InstallPlan, error) { + return ip, ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(ip), ip) + }).Should(And(HavePhase(operatorsv1alpha1.InstallPlanPhaseInstalling)), HaveMessage(errMessage)) - // Eventually the IP fails with the GVK missing error, after installplan retries, which is by default 1 minute. - Eventually(func() (*operatorsv1alpha1.InstallPlan, error) { - return tt.IP, ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(tt.IP), tt.IP) - }, 2*time.Minute).Should(And(HavePhase(operatorsv1alpha1.InstallPlanPhaseFailed)), HaveMessage(tt.errMessage)) - }, tableEntries...) + // Eventually the IP fails with the GVK missing error, after installplan retries, which is by default 1 minute. + Eventually(func() (*operatorsv1alpha1.InstallPlan, error) { + return ip, ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(ip), ip) + }, 2*time.Minute).Should(And(HavePhase(operatorsv1alpha1.InstallPlanPhaseFailed)), HaveMessage(errMessage)) + }) + }) }) }) diff --git a/staging/operator-lifecycle-manager/test/e2e/e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/e2e_test.go index ac137e5861..0d0f4eb845 100644 --- a/staging/operator-lifecycle-manager/test/e2e/e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/e2e_test.go @@ -42,6 +42,12 @@ var ( "dummy image to treat as an operator in tests", ) + collectArtifactsScriptPath = flag.String( + "gather-artifacts-script-path", + "./collect-ci-artifacts.sh", + "configures the relative/absolute path to the script resposible for collecting CI artifacts", + ) + testdataPath = flag.String( "test-data-dir", "./testdata", @@ -82,6 +88,9 @@ var _ = BeforeSuite(func() { // This flag can be deprecated in favor of the kubeconfig provisioner: os.Setenv("KUBECONFIG", *kubeConfigPath) } + if collectArtifactsScriptPath != nil && *collectArtifactsScriptPath != "" { + os.Setenv("E2E_ARTIFACTS_SCRIPT", *collectArtifactsScriptPath) + } testNamespace = *namespace operatorNamespace = *olmNamespace diff --git a/staging/operator-lifecycle-manager/test/e2e/gc_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/gc_e2e_test.go index d5627d5bca..3150df1edb 100644 --- a/staging/operator-lifecycle-manager/test/e2e/gc_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/gc_e2e_test.go @@ -11,7 +11,7 @@ import ( corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/rand" apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1" @@ -27,15 +27,19 @@ var _ = Describe("Garbage collection for dependent resources", func() { var ( kubeClient operatorclient.ClientInterface operatorClient versioned.Interface + ns corev1.Namespace ) BeforeEach(func() { kubeClient = ctx.Ctx().KubeClient() operatorClient = ctx.Ctx().OperatorClient() + + namespaceName := genName("gc-e2e-") + ns = SetupGeneratedTestNamespace(namespaceName, namespaceName) }) AfterEach(func() { - TearDown(testNamespace) + TeardownNamespace(ns.GetName()) }) Context("Given a ClusterRole owned by a CustomResourceDefinition", func() { @@ -109,14 +113,14 @@ var _ = Describe("Garbage collection for dependent resources", func() { // Delete CRD Eventually(func() bool { err := kubeClient.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), crd.GetName(), metav1.DeleteOptions{}) - return k8serrors.IsNotFound(err) + return apierrors.IsNotFound(err) }).Should(BeTrue()) }) It("should delete the associated ClusterRole", func() { Eventually(func() bool { _, err := kubeClient.GetClusterRole(cr.GetName()) - return k8serrors.IsNotFound(err) + return apierrors.IsNotFound(err) }).Should(BeTrue(), "get cluster role should eventually return \"not found\"") }) @@ -179,14 +183,14 @@ var _ = Describe("Garbage collection for dependent resources", func() { // Delete API service Eventually(func() bool { err := kubeClient.DeleteAPIService(apiService.GetName(), &metav1.DeleteOptions{}) - return k8serrors.IsNotFound(err) + return apierrors.IsNotFound(err) }).Should(BeTrue()) }) It("should delete the associated ClusterRole", func() { Eventually(func() bool { _, err := kubeClient.GetClusterRole(cr.GetName()) - return k8serrors.IsNotFound(err) + return apierrors.IsNotFound(err) }).Should(BeTrue(), "get cluster role should eventually return \"not found\"") }) @@ -214,18 +218,18 @@ var _ = Describe("Garbage collection for dependent resources", func() { ) BeforeEach(func() { - ownerA = newCSV("ownera", testNamespace, "", semver.MustParse("0.0.0"), nil, nil, nil) - ownerB = newCSV("ownerb", testNamespace, "", semver.MustParse("0.0.0"), nil, nil, nil) + ownerA = newCSV("ownera", ns.GetName(), "", semver.MustParse("0.0.0"), nil, nil, nil) + ownerB = newCSV("ownerb", ns.GetName(), "", semver.MustParse("0.0.0"), nil, nil, nil) // create all owners var err error Eventually(func() error { - fetchedA, err = operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Create(context.Background(), &ownerA, metav1.CreateOptions{}) + fetchedA, err = operatorClient.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Create(context.Background(), &ownerA, metav1.CreateOptions{}) return err }).Should(Succeed()) Eventually(func() error { - fetchedB, err = operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Create(context.Background(), &ownerB, metav1.CreateOptions{}) + fetchedB, err = operatorClient.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Create(context.Background(), &ownerB, metav1.CreateOptions{}) return err }).Should(Succeed()) @@ -242,7 +246,7 @@ var _ = Describe("Garbage collection for dependent resources", func() { // create ConfigMap dependent Eventually(func() error { - _, err = kubeClient.KubernetesInterface().CoreV1().ConfigMaps(testNamespace).Create(context.Background(), dependent, metav1.CreateOptions{}) + _, err = kubeClient.KubernetesInterface().CoreV1().ConfigMaps(ns.GetName()).Create(context.Background(), dependent, metav1.CreateOptions{}) return err }).Should(Succeed(), "dependent could not be created") @@ -255,20 +259,20 @@ var _ = Describe("Garbage collection for dependent resources", func() { BeforeEach(func() { // delete ownerA in the foreground (to ensure any "blocking" dependents are deleted before ownerA) Eventually(func() bool { - err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Delete(context.Background(), fetchedA.GetName(), options) - return k8serrors.IsNotFound(err) + err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Delete(context.Background(), fetchedA.GetName(), options) + return apierrors.IsNotFound(err) }).Should(BeTrue()) // wait for deletion of ownerA Eventually(func() bool { - _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Get(context.Background(), ownerA.GetName(), metav1.GetOptions{}) - return k8serrors.IsNotFound(err) + _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Get(context.Background(), ownerA.GetName(), metav1.GetOptions{}) + return apierrors.IsNotFound(err) }).Should(BeTrue()) }) It("should not have deleted the dependent since ownerB CSV is still present", func() { Eventually(func() error { - _, err := kubeClient.KubernetesInterface().CoreV1().ConfigMaps(testNamespace).Get(context.Background(), dependent.GetName(), metav1.GetOptions{}) + _, err := kubeClient.KubernetesInterface().CoreV1().ConfigMaps(ns.GetName()).Get(context.Background(), dependent.GetName(), metav1.GetOptions{}) return err }).Should(Succeed(), "dependent deleted after one of the owner was deleted") ctx.Ctx().Logf("dependent still exists after one owner was deleted") @@ -280,33 +284,33 @@ var _ = Describe("Garbage collection for dependent resources", func() { BeforeEach(func() { // delete ownerA in the foreground (to ensure any "blocking" dependents are deleted before ownerA) Eventually(func() bool { - err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Delete(context.Background(), fetchedA.GetName(), options) - return k8serrors.IsNotFound(err) + err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Delete(context.Background(), fetchedA.GetName(), options) + return apierrors.IsNotFound(err) }).Should(BeTrue()) // wait for deletion of ownerA Eventually(func() bool { - _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Get(context.Background(), ownerA.GetName(), metav1.GetOptions{}) - return k8serrors.IsNotFound(err) + _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Get(context.Background(), ownerA.GetName(), metav1.GetOptions{}) + return apierrors.IsNotFound(err) }).Should(BeTrue()) // delete ownerB in the foreground (to ensure any "blocking" dependents are deleted before ownerB) Eventually(func() bool { - err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Delete(context.Background(), fetchedB.GetName(), options) - return k8serrors.IsNotFound(err) + err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Delete(context.Background(), fetchedB.GetName(), options) + return apierrors.IsNotFound(err) }).Should(BeTrue()) // wait for deletion of ownerB Eventually(func() bool { - _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Get(context.Background(), ownerB.GetName(), metav1.GetOptions{}) - return k8serrors.IsNotFound(err) + _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Get(context.Background(), ownerB.GetName(), metav1.GetOptions{}) + return apierrors.IsNotFound(err) }).Should(BeTrue()) }) It("should have deleted the dependent since both the owners were deleted", func() { Eventually(func() bool { - _, err := kubeClient.KubernetesInterface().CoreV1().ConfigMaps(testNamespace).Get(context.Background(), dependent.GetName(), metav1.GetOptions{}) - return k8serrors.IsNotFound(err) + _, err := kubeClient.KubernetesInterface().CoreV1().ConfigMaps(ns.GetName()).Get(context.Background(), dependent.GetName(), metav1.GetOptions{}) + return apierrors.IsNotFound(err) }).Should(BeTrue(), "expected dependency configmap would be properly garabage collected") ctx.Ctx().Logf("dependent successfully garbage collected after both owners were deleted") }) @@ -339,7 +343,7 @@ var _ = Describe("Garbage collection for dependent resources", func() { }, ObjectMeta: metav1.ObjectMeta{ Name: sourceName, - Namespace: testNamespace, + Namespace: ns.GetName(), Labels: map[string]string{"olm.catalogSource": sourceName}, }, Spec: v1alpha1.CatalogSourceSpec{ @@ -366,25 +370,25 @@ var _ = Describe("Garbage collection for dependent resources", func() { _ = createSubscriptionForCatalog(operatorClient, source.GetNamespace(), subName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic) // Wait for the Subscription to succeed - sub, err := fetchSubscription(operatorClient, testNamespace, subName, subscriptionStateAtLatestChecker) + sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker) Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") installPlanRef = sub.Status.InstallPlanRef.Name // Wait for the installplan to complete (5 minute timeout) - _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, testNamespace, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) + _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, ns.GetName(), buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) Expect(err).ToNot(HaveOccurred(), "could not get installplan at complete phase") ctx.Ctx().Logf("install plan %s completed", installPlanRef) // confirm extra bundle objects (secret and configmap) are installed Eventually(func() error { - _, err := kubeClient.GetSecret(testNamespace, secretName) + _, err := kubeClient.GetSecret(ns.GetName(), secretName) return err }).Should(Succeed(), "expected no error getting secret object associated with CSV") Eventually(func() error { - _, err := kubeClient.GetConfigMap(testNamespace, configmapName) + _, err := kubeClient.GetConfigMap(ns.GetName(), configmapName) return err }).Should(Succeed(), "expected no error getting configmap object associated with CSV") }) @@ -395,39 +399,39 @@ var _ = Describe("Garbage collection for dependent resources", func() { BeforeEach(func() { // Delete subscription first Eventually(func() bool { - err := operatorClient.OperatorsV1alpha1().Subscriptions(testNamespace).Delete(context.Background(), subName, metav1.DeleteOptions{}) - return k8serrors.IsNotFound(err) + err := operatorClient.OperatorsV1alpha1().Subscriptions(ns.GetName()).Delete(context.Background(), subName, metav1.DeleteOptions{}) + return apierrors.IsNotFound(err) }).Should(BeTrue()) // wait for deletion Eventually(func() bool { - _, err := operatorClient.OperatorsV1alpha1().Subscriptions(testNamespace).Get(context.Background(), subName, metav1.GetOptions{}) - return k8serrors.IsNotFound(err) + _, err := operatorClient.OperatorsV1alpha1().Subscriptions(ns.GetName()).Get(context.Background(), subName, metav1.GetOptions{}) + return apierrors.IsNotFound(err) }).Should(BeTrue()) // Delete CSV Eventually(func() bool { - err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Delete(context.Background(), csvName, metav1.DeleteOptions{}) - return k8serrors.IsNotFound(err) + err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Delete(context.Background(), csvName, metav1.DeleteOptions{}) + return apierrors.IsNotFound(err) }).Should(BeTrue()) // wait for deletion Eventually(func() bool { - _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Get(context.Background(), csvName, metav1.GetOptions{}) - return k8serrors.IsNotFound(err) + _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Get(context.Background(), csvName, metav1.GetOptions{}) + return apierrors.IsNotFound(err) }).Should(BeTrue()) }) It("OLM should delete the associated configmap and secret", func() { // confirm extra bundle objects (secret and configmap) are no longer installed on the cluster Eventually(func() bool { - _, err := kubeClient.GetSecret(testNamespace, secretName) - return k8serrors.IsNotFound(err) + _, err := kubeClient.GetSecret(ns.GetName(), secretName) + return apierrors.IsNotFound(err) }).Should(BeTrue()) Eventually(func() bool { - _, err := kubeClient.GetConfigMap(testNamespace, configmapName) - return k8serrors.IsNotFound(err) + _, err := kubeClient.GetConfigMap(ns.GetName(), configmapName) + return apierrors.IsNotFound(err) }).Should(BeTrue()) ctx.Ctx().Logf("dependent successfully garbage collected after csv owner was deleted") }) @@ -457,7 +461,7 @@ var _ = Describe("Garbage collection for dependent resources", func() { }, ObjectMeta: metav1.ObjectMeta{ Name: sourceName, - Namespace: testNamespace, + Namespace: ns.GetName(), Labels: map[string]string{"olm.catalogSource": sourceName}, }, Spec: v1alpha1.CatalogSourceSpec{ @@ -480,17 +484,17 @@ var _ = Describe("Garbage collection for dependent resources", func() { _ = createSubscriptionForCatalog(operatorClient, source.GetNamespace(), subName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic) // Wait for the Subscription to succeed - sub, err := fetchSubscription(operatorClient, testNamespace, subName, subscriptionStateAtLatestChecker) + sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker) Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") installPlanRef = sub.Status.InstallPlanRef.Name // Wait for the installplan to complete (5 minute timeout) - _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, testNamespace, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) + _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, ns.GetName(), buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) Expect(err).ToNot(HaveOccurred(), "could not get installplan at complete phase") Eventually(func() error { - _, err := kubeClient.GetConfigMap(testNamespace, configmapName) + _, err := kubeClient.GetConfigMap(ns.GetName(), configmapName) return err }).Should(Succeed(), "expected no error getting configmap object associated with CSV") }) @@ -505,36 +509,36 @@ var _ = Describe("Garbage collection for dependent resources", func() { BeforeEach(func() { Eventually(func() error { // update subscription first - sub, err := operatorClient.OperatorsV1alpha1().Subscriptions(testNamespace).Get(context.Background(), subName, metav1.GetOptions{}) + sub, err := operatorClient.OperatorsV1alpha1().Subscriptions(ns.GetName()).Get(context.Background(), subName, metav1.GetOptions{}) if err != nil { return fmt.Errorf("could not get subscription") } // update channel on sub sub.Spec.Channel = upgradeChannelName - _, err = operatorClient.OperatorsV1alpha1().Subscriptions(testNamespace).Update(context.Background(), sub, metav1.UpdateOptions{}) + _, err = operatorClient.OperatorsV1alpha1().Subscriptions(ns.GetName()).Update(context.Background(), sub, metav1.UpdateOptions{}) return err }).Should(Succeed(), "could not update subscription") // Wait for the Subscription to succeed - sub, err := fetchSubscription(operatorClient, testNamespace, subName, subscriptionStateAtLatestChecker) + sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker) Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") installPlanRef = sub.Status.InstallPlanRef.Name // Wait for the installplan to complete (5 minute timeout) - _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, testNamespace, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) + _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, ns.GetName(), buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) Expect(err).ToNot(HaveOccurred(), "could not get installplan at complete phase") // Ensure the new csv is installed Eventually(func() error { - _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Get(context.Background(), newCSVname, metav1.GetOptions{}) + _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Get(context.Background(), newCSVname, metav1.GetOptions{}) return err }).Should(BeNil()) }) It("OLM should have upgraded associated configmap in place", func() { Eventually(func() (string, error) { - cfg, err := kubeClient.GetConfigMap(testNamespace, configmapName) + cfg, err := kubeClient.GetConfigMap(ns.GetName(), configmapName) if err != nil { return "", err } @@ -570,7 +574,7 @@ var _ = Describe("Garbage collection for dependent resources", func() { }, ObjectMeta: metav1.ObjectMeta{ Name: sourceName, - Namespace: testNamespace, + Namespace: ns.GetName(), Labels: map[string]string{"olm.catalogSource": sourceName}, }, Spec: v1alpha1.CatalogSourceSpec{ @@ -593,17 +597,17 @@ var _ = Describe("Garbage collection for dependent resources", func() { _ = createSubscriptionForCatalog(operatorClient, source.GetNamespace(), subName, source.GetName(), packageName, channelName, "", v1alpha1.ApprovalAutomatic) // Wait for the Subscription to succeed - sub, err := fetchSubscription(operatorClient, testNamespace, subName, subscriptionStateAtLatestChecker) + sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker) Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") installPlanRef = sub.Status.InstallPlanRef.Name // Wait for the installplan to complete (5 minute timeout) - _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, testNamespace, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) + _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, ns.GetName(), buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) Expect(err).ToNot(HaveOccurred(), "could not get installplan at complete phase") Eventually(func() error { - _, err := kubeClient.GetConfigMap(testNamespace, configmapName) + _, err := kubeClient.GetConfigMap(ns.GetName(), configmapName) return err }).Should(Succeed(), "expected no error getting configmap object associated with CSV") }) @@ -619,29 +623,29 @@ var _ = Describe("Garbage collection for dependent resources", func() { BeforeEach(func() { Eventually(func() error { // update subscription first - sub, err := operatorClient.OperatorsV1alpha1().Subscriptions(testNamespace).Get(context.Background(), subName, metav1.GetOptions{}) + sub, err := operatorClient.OperatorsV1alpha1().Subscriptions(ns.GetName()).Get(context.Background(), subName, metav1.GetOptions{}) if err != nil { return fmt.Errorf("could not get subscription") } // update channel on sub sub.Spec.Channel = upgradeChannelName - _, err = operatorClient.OperatorsV1alpha1().Subscriptions(testNamespace).Update(context.Background(), sub, metav1.UpdateOptions{}) + _, err = operatorClient.OperatorsV1alpha1().Subscriptions(ns.GetName()).Update(context.Background(), sub, metav1.UpdateOptions{}) return err }).Should(Succeed(), "could not update subscription") // Wait for the Subscription to succeed - sub, err := fetchSubscription(operatorClient, testNamespace, subName, subscriptionStateAtLatestChecker) + sub, err := fetchSubscription(operatorClient, ns.GetName(), subName, subscriptionStateAtLatestChecker) Expect(err).ToNot(HaveOccurred(), "could not get subscription at latest status") installPlanRef = sub.Status.InstallPlanRef.Name // Wait for the installplan to complete (5 minute timeout) - _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, testNamespace, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) + _, err = fetchInstallPlan(GinkgoT(), operatorClient, installPlanRef, ns.GetName(), buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete)) Expect(err).ToNot(HaveOccurred(), "could not get installplan at complete phase") // Ensure the new csv is installed Eventually(func() error { - _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Get(context.Background(), newCSVname, metav1.GetOptions{}) + _, err := operatorClient.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Get(context.Background(), newCSVname, metav1.GetOptions{}) return err }).Should(BeNil()) }) @@ -649,12 +653,12 @@ var _ = Describe("Garbage collection for dependent resources", func() { // flake issue: https://github.com/operator-framework/operator-lifecycle-manager/issues/2626 It("[FLAKE] should have removed the old configmap and put the new configmap in place", func() { Eventually(func() bool { - _, err := kubeClient.GetConfigMap(testNamespace, configmapName) - return k8serrors.IsNotFound(err) + _, err := kubeClient.GetConfigMap(ns.GetName(), configmapName) + return apierrors.IsNotFound(err) }).Should(BeTrue()) Eventually(func() error { - _, err := kubeClient.GetConfigMap(testNamespace, upgradedConfigMapName) + _, err := kubeClient.GetConfigMap(ns.GetName(), upgradedConfigMapName) return err }).Should(BeNil()) ctx.Ctx().Logf("dependent successfully updated after csv owner was updated") diff --git a/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go index 0516dff258..3583670b2e 100644 --- a/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/installplan_e2e_test.go @@ -26,7 +26,7 @@ import ( "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/equality" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" @@ -52,12 +52,28 @@ import ( ) var _ = Describe("Install Plan", func() { + + var ns corev1.Namespace + + BeforeEach(func() { + namespaceName := genName("install-plan-e2e-") + og := operatorsv1.OperatorGroup{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-operatorgroup", namespaceName), + Namespace: namespaceName, + }, + } + ns = SetupGeneratedTestNamespaceWithOperatorGroup(namespaceName, og) + }) + AfterEach(func() { - TearDown(testNamespace) + TeardownNamespace(ns.GetName()) }) When("an InstallPlan step contains a deprecated resource version", func() { var ( + csv operatorsv1alpha1.ClusterServiceVersion + plan operatorsv1alpha1.InstallPlan pdb policyv1beta1.PodDisruptionBudget manifest string counter float64 @@ -88,12 +104,12 @@ var _ = Describe("Install Plan", func() { } } - csv := newCSV("test-csv", testNamespace, "", semver.Version{}, nil, nil, nil) - Expect(ctx.Ctx().Client().Create(context.TODO(), &csv)).To(Succeed()) + csv = newCSV(genName("test-csv-"), ns.GetName(), "", semver.Version{}, nil, nil, nil) + Expect(ctx.Ctx().Client().Create(context.Background(), &csv)).To(Succeed()) pdb = policyv1beta1.PodDisruptionBudget{ ObjectMeta: metav1.ObjectMeta{ - Name: "test-pdb", + Name: genName("test-pdb-"), }, TypeMeta: metav1.TypeMeta{ Kind: "PodDisruptionBudget", @@ -110,10 +126,10 @@ var _ = Describe("Install Plan", func() { manifest = b.String() } - plan := operatorsv1alpha1.InstallPlan{ + plan = operatorsv1alpha1.InstallPlan{ ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, - Name: "test-plan", + Namespace: ns.GetName(), + Name: genName("test-plan-"), }, Spec: operatorsv1alpha1.InstallPlanSpec{ Approval: operatorsv1alpha1.ApprovalAutomatic, @@ -127,7 +143,7 @@ var _ = Describe("Install Plan", func() { CatalogSources: []string{}, Plan: []*operatorsv1alpha1.Step{ { - Resolving: "test-csv", + Resolving: csv.GetName(), Status: operatorsv1alpha1.StepStatusUnknown, Resource: operatorsv1alpha1.StepResource{ Name: pdb.GetName(), @@ -142,13 +158,18 @@ var _ = Describe("Install Plan", func() { Eventually(func() (*operatorsv1alpha1.InstallPlan, error) { return &plan, ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&plan), &plan) }).Should(HavePhase(operatorsv1alpha1.InstallPlanPhaseComplete)) + }) + AfterEach(func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), &csv)) + }).Should(Succeed()) }) It("creates an Event surfacing the deprecation warning", func() { Eventually(func() ([]corev1.Event, error) { var events corev1.EventList - if err := ctx.Ctx().Client().List(context.Background(), &events, client.InNamespace(testNamespace)); err != nil { + if err := ctx.Ctx().Client().List(context.Background(), &events, client.InNamespace(ns.GetName())); err != nil { return nil, err } var result []corev1.Event @@ -170,12 +191,12 @@ var _ = Describe("Install Plan", func() { InvolvedObject: corev1.ObjectReference{ APIVersion: operatorsv1alpha1.InstallPlanAPIVersion, Kind: operatorsv1alpha1.InstallPlanKind, - Namespace: testNamespace, - Name: "test-plan", + Namespace: ns.GetName(), + Name: plan.GetName(), FieldPath: "status.plan[0]", }, Reason: "AppliedWithWarnings", - Message: "1 warning(s) generated during installation of operator \"test-csv\" (PodDisruptionBudget \"test-pdb\"): policy/v1beta1 PodDisruptionBudget is deprecated in v1.21+, unavailable in v1.25+; use policy/v1 PodDisruptionBudget", + Message: fmt.Sprintf("1 warning(s) generated during installation of operator \"%s\" (PodDisruptionBudget \"%s\"): policy/v1beta1 PodDisruptionBudget is deprecated in v1.21+, unavailable in v1.25+; use policy/v1 PodDisruptionBudget", csv.GetName(), pdb.GetName()), })) }) @@ -197,8 +218,8 @@ var _ = Describe("Install Plan", func() { ) BeforeEach(func() { - csv := newCSV("test-csv", testNamespace, "", semver.Version{}, nil, nil, nil) - Expect(ctx.Ctx().Client().Create(context.TODO(), &csv)).To(Succeed()) + csv := newCSV("test-csv", ns.GetName(), "", semver.Version{}, nil, nil, nil) + Expect(ctx.Ctx().Client().Create(context.Background(), &csv)).To(Succeed()) crd = apiextensionsv1.CustomResourceDefinition{ ObjectMeta: metav1.ObjectMeta{ @@ -240,7 +261,7 @@ var _ = Describe("Install Plan", func() { plan := operatorsv1alpha1.InstallPlan{ ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, + Namespace: ns.GetName(), Name: "test-plan", }, Spec: operatorsv1alpha1.InstallPlanSpec{ @@ -274,8 +295,8 @@ var _ = Describe("Install Plan", func() { AfterEach(func() { Eventually(func() error { - return ctx.Ctx().Client().Delete(context.Background(), &crd) - }).Should(WithTransform(k8serrors.IsNotFound, BeTrue())) + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), crd.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) }) It("is annotated with a reference to its associated ClusterServiceVersion", func() { @@ -286,18 +307,22 @@ var _ = Describe("Install Plan", func() { return crd.GetAnnotations(), nil }).Should(HaveKeyWithValue( HavePrefix("operatorframework.io/installed-alongside-"), - fmt.Sprintf("%s/test-csv", testNamespace), + fmt.Sprintf("%s/test-csv", ns.GetName()), )) }) When("a second plan includes the same CustomResourceDefinition", func() { + var ( + csv operatorsv1alpha1.ClusterServiceVersion + plan operatorsv1alpha1.InstallPlan + ) BeforeEach(func() { - csv := newCSV("test-csv-two", testNamespace, "", semver.Version{}, nil, nil, nil) - Expect(ctx.Ctx().Client().Create(context.TODO(), &csv)).To(Succeed()) + csv = newCSV("test-csv-two", ns.GetName(), "", semver.Version{}, nil, nil, nil) + Expect(ctx.Ctx().Client().Create(context.Background(), &csv)).To(Succeed()) - plan := operatorsv1alpha1.InstallPlan{ + plan = operatorsv1alpha1.InstallPlan{ ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, + Namespace: ns.GetName(), Name: "test-plan-two", }, Spec: operatorsv1alpha1.InstallPlanSpec{ @@ -329,6 +354,15 @@ var _ = Describe("Install Plan", func() { }).Should(HavePhase(operatorsv1alpha1.InstallPlanPhaseComplete)) }) + AfterEach(func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), &csv)) + }).Should(Succeed()) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), &plan)) + }).Should(Succeed()) + }) + It("has one annotation for each ClusterServiceVersion", func() { Eventually(func() ([]struct{ Key, Value string }, error) { if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&crd), &crd); err != nil { @@ -342,11 +376,11 @@ var _ = Describe("Install Plan", func() { }).Should(ConsistOf( MatchFields(IgnoreExtras, Fields{ "Key": HavePrefix("operatorframework.io/installed-alongside-"), - "Value": Equal(fmt.Sprintf("%s/test-csv", testNamespace)), + "Value": Equal(fmt.Sprintf("%s/test-csv", ns.GetName())), }), MatchFields(IgnoreExtras, Fields{ "Key": HavePrefix("operatorframework.io/installed-alongside-"), - "Value": Equal(fmt.Sprintf("%s/test-csv-two", testNamespace)), + "Value": Equal(fmt.Sprintf("%s/test-csv-two", ns.GetName())), }), )) }) @@ -367,7 +401,7 @@ var _ = Describe("Install Plan", func() { // during a test. owned = &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, + Namespace: ns.GetName(), Name: "test-owned", OwnerReferences: []metav1.OwnerReference{{ APIVersion: "operators.coreos.com/v1alpha1", @@ -385,7 +419,7 @@ var _ = Describe("Install Plan", func() { plan = &operatorsv1alpha1.InstallPlan{ ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, + Namespace: ns.GetName(), Name: "test-plan", }, Spec: operatorsv1alpha1.InstallPlanSpec{ @@ -416,7 +450,11 @@ var _ = Describe("Install Plan", func() { AfterEach(func() { Expect(ctx.Ctx().Client().Delete(context.Background(), owned)).To(Or( Succeed(), - WithTransform(k8serrors.IsNotFound, BeTrue()), + WithTransform(apierrors.IsNotFound, BeTrue()), + )) + Expect(ctx.Ctx().Client().Delete(context.Background(), plan)).To(Or( + Succeed(), + WithTransform(apierrors.IsNotFound, BeTrue()), )) }) @@ -430,7 +468,7 @@ var _ = Describe("Install Plan", func() { }) It("succeeds if there is no error on a later attempt", func() { - owner := newCSV("test-owner", testNamespace, "", semver.Version{}, nil, nil, nil) + owner := newCSV("test-owner", ns.GetName(), "", semver.Version{}, nil, nil, nil) Expect(ctx.Ctx().Client().Create(context.Background(), &owner)).To(Succeed()) Eventually(func() (*operatorsv1alpha1.InstallPlan, error) { return plan, ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(plan), plan) @@ -446,14 +484,14 @@ var _ = Describe("Install Plan", func() { ) BeforeEach(func() { - csv1 = newCSV("test-csv-old", testNamespace, "", semver.Version{}, nil, nil, nil) - Expect(ctx.Ctx().Client().Create(context.TODO(), &csv1)).To(Succeed()) - csv2 = newCSV("test-csv-new", testNamespace, "", semver.Version{}, nil, nil, nil) - Expect(ctx.Ctx().Client().Create(context.TODO(), &csv2)).To(Succeed()) + csv1 = newCSV("test-csv-old", ns.GetName(), "", semver.Version{}, nil, nil, nil) + Expect(ctx.Ctx().Client().Create(context.Background(), &csv1)).To(Succeed()) + csv2 = newCSV("test-csv-new", ns.GetName(), "", semver.Version{}, nil, nil, nil) + Expect(ctx.Ctx().Client().Create(context.Background(), &csv2)).To(Succeed()) sa = corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, + Namespace: ns.GetName(), Name: "test-serviceaccount", OwnerReferences: []metav1.OwnerReference{ { @@ -465,14 +503,14 @@ var _ = Describe("Install Plan", func() { }, }, } - Expect(ctx.Ctx().Client().Create(context.TODO(), &sa)).To(Succeed()) + Expect(ctx.Ctx().Client().Create(context.Background(), &sa)).To(Succeed()) scheme := runtime.NewScheme() Expect(corev1.AddToScheme(scheme)).To(Succeed()) var manifest bytes.Buffer Expect(k8sjson.NewSerializer(k8sjson.DefaultMetaFactory, scheme, scheme, false).Encode(&corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, + Namespace: ns.GetName(), Name: "test-serviceaccount", OwnerReferences: []metav1.OwnerReference{ { @@ -486,7 +524,7 @@ var _ = Describe("Install Plan", func() { plan = operatorsv1alpha1.InstallPlan{ ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, + Namespace: ns.GetName(), Name: "test-plan", }, Spec: operatorsv1alpha1.InstallPlanSpec{ @@ -515,15 +553,27 @@ var _ = Describe("Install Plan", func() { }) AfterEach(func() { - Expect(ctx.Ctx().Client().Delete(context.TODO(), &sa)).To(Or( + Expect(ctx.Ctx().Client().Delete(context.Background(), &sa)).To(Or( + Succeed(), + WithTransform(apierrors.IsNotFound, BeTrue()), + )) + Expect(ctx.Ctx().Client().Delete(context.Background(), &csv1)).To(Or( + Succeed(), + WithTransform(apierrors.IsNotFound, BeTrue()), + )) + Expect(ctx.Ctx().Client().Delete(context.Background(), &csv2)).To(Or( + Succeed(), + WithTransform(apierrors.IsNotFound, BeTrue()), + )) + Expect(ctx.Ctx().Client().Delete(context.Background(), &plan)).To(Or( Succeed(), - WithTransform(k8serrors.IsNotFound, BeTrue()), + WithTransform(apierrors.IsNotFound, BeTrue()), )) }) It("preserves owner references to both the old and the new ClusterServiceVersion", func() { Eventually(func() ([]metav1.OwnerReference, error) { - if err := ctx.Ctx().Client().Get(context.TODO(), client.ObjectKeyFromObject(&sa), &sa); err != nil { + if err := ctx.Ctx().Client().Get(context.Background(), client.ObjectKeyFromObject(&sa), &sa); err != nil { return nil, err } return sa.GetOwnerReferences(), nil @@ -556,7 +606,7 @@ var _ = Describe("Install Plan", func() { APIVersion: "v1", }, ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, + Namespace: ns.GetName(), Name: "test-service", }, Spec: corev1.ServiceSpec{ @@ -584,7 +634,7 @@ var _ = Describe("Install Plan", func() { plan := &operatorsv1alpha1.InstallPlan{ ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, + Namespace: ns.GetName(), Name: "test-plan", }, Spec: operatorsv1alpha1.InstallPlanSpec{ @@ -617,6 +667,7 @@ var _ = Describe("Install Plan", func() { Eventually(func() (*operatorsv1alpha1.InstallPlan, error) { return plan, ctx.Ctx().Client().Get(context.Background(), key, plan) }).Should(HavePhase(operatorsv1alpha1.InstallPlanPhaseComplete)) + Expect(client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), plan))).To(Succeed()) }) }) @@ -635,13 +686,13 @@ var _ = Describe("Install Plan", func() { stableChannel := "stable" dependentCRD := newCRD(genName("ins-")) - mainCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), nil, []apiextensions.CustomResourceDefinition{dependentCRD}, nil) - dependentCSV := newCSV(dependentPackageStable, testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{dependentCRD}, nil, nil) + mainCSV := newCSV(mainPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), nil, []apiextensions.CustomResourceDefinition{dependentCRD}, nil) + dependentCSV := newCSV(dependentPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{dependentCRD}, nil, nil) c := newKubeClient() crc := newCRClient() defer func() { - require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(testNamespace).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})) + require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(ns.GetName()).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{})) }() dependentCatalogName := genName("mock-ocs-dependent-") @@ -668,49 +719,56 @@ var _ = Describe("Install Plan", func() { }, } + // Defer CRD clean up + defer func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), dependentCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + }() + // Create the catalog sources - require.NotEqual(GinkgoT(), "", testNamespace) - _, cleanupDependentCatalogSource := createInternalCatalogSource(c, crc, dependentCatalogName, testNamespace, dependentManifests, []apiextensions.CustomResourceDefinition{dependentCRD}, []operatorsv1alpha1.ClusterServiceVersion{dependentCSV}) + require.NotEqual(GinkgoT(), "", ns.GetName()) + _, cleanupDependentCatalogSource := createInternalCatalogSource(c, crc, dependentCatalogName, ns.GetName(), dependentManifests, []apiextensions.CustomResourceDefinition{dependentCRD}, []operatorsv1alpha1.ClusterServiceVersion{dependentCSV}) defer cleanupDependentCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, dependentCatalogName, testNamespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, dependentCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) - _, cleanupMainCatalogSource := createInternalCatalogSource(c, crc, mainCatalogName, testNamespace, mainManifests, nil, []operatorsv1alpha1.ClusterServiceVersion{mainCSV}) + _, cleanupMainCatalogSource := createInternalCatalogSource(c, crc, mainCatalogName, ns.GetName(), mainManifests, nil, []operatorsv1alpha1.ClusterServiceVersion{mainCSV}) defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating install plan - _, err = fetchCatalogSourceOnStatus(crc, mainCatalogName, testNamespace, catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) // Create expected install plan step sources expectedStepSources := map[registry.ResourceKey]registry.ResourceKey{ - {Name: dependentCRD.Name, Kind: "CustomResourceDefinition"}: {Name: dependentCatalogName, Namespace: testNamespace}, - {Name: dependentPackageStable, Kind: operatorsv1alpha1.ClusterServiceVersionKind}: {Name: dependentCatalogName, Namespace: testNamespace}, - {Name: mainPackageStable, Kind: operatorsv1alpha1.ClusterServiceVersionKind}: {Name: mainCatalogName, Namespace: testNamespace}, - {Name: strings.Join([]string{dependentPackageStable, dependentCatalogName, testNamespace}, "-"), Kind: operatorsv1alpha1.SubscriptionKind}: {Name: dependentCatalogName, Namespace: testNamespace}, + {Name: dependentCRD.Name, Kind: "CustomResourceDefinition"}: {Name: dependentCatalogName, Namespace: ns.GetName()}, + {Name: dependentPackageStable, Kind: operatorsv1alpha1.ClusterServiceVersionKind}: {Name: dependentCatalogName, Namespace: ns.GetName()}, + {Name: mainPackageStable, Kind: operatorsv1alpha1.ClusterServiceVersionKind}: {Name: mainCatalogName, Namespace: ns.GetName()}, + {Name: strings.Join([]string{dependentPackageStable, dependentCatalogName, ns.GetName()}, "-"), Kind: operatorsv1alpha1.SubscriptionKind}: {Name: dependentCatalogName, Namespace: ns.GetName()}, } subscriptionName := genName("sub-nginx-") - subscriptionCleanup := createSubscriptionForCatalog(crc, testNamespace, subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) installPlanName := subscription.Status.InstallPlanRef.Name // Wait for InstallPlan to be status: Complete before checking resource presence - fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) + fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) require.NoError(GinkgoT(), err) log(fmt.Sprintf("Install plan %s fetched with status %s", fetchedInstallPlan.GetName(), fetchedInstallPlan.Status.Phase)) require.Equal(GinkgoT(), operatorsv1alpha1.InstallPlanPhaseComplete, fetchedInstallPlan.Status.Phase) // Fetch installplan again to check for unnecessary control loops - fetchedInstallPlan, err = fetchInstallPlan(GinkgoT(), crc, fetchedInstallPlan.GetName(), testNamespace, func(fip *operatorsv1alpha1.InstallPlan) bool { + fetchedInstallPlan, err = fetchInstallPlan(GinkgoT(), crc, fetchedInstallPlan.GetName(), ns.GetName(), func(fip *operatorsv1alpha1.InstallPlan) bool { // Don't compare object meta as labels can be applied by the operator controller. Expect(equality.Semantic.DeepEqual(fetchedInstallPlan.Spec, fip.Spec)).Should(BeTrue(), diff.ObjectDiff(fetchedInstallPlan, fip)) Expect(equality.Semantic.DeepEqual(fetchedInstallPlan.Status, fip.Status)).Should(BeTrue(), diff.ObjectDiff(fetchedInstallPlan, fip)) @@ -744,18 +802,18 @@ var _ = Describe("Install Plan", func() { log("All expected resources resolved") // Verify that the dependent subscription is in a good state - dependentSubscription, err := fetchSubscription(crc, testNamespace, strings.Join([]string{dependentPackageStable, dependentCatalogName, testNamespace}, "-"), subscriptionStateAtLatestChecker) + dependentSubscription, err := fetchSubscription(crc, ns.GetName(), strings.Join([]string{dependentPackageStable, dependentCatalogName, ns.GetName()}, "-"), subscriptionStateAtLatestChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), dependentSubscription) require.NotNil(GinkgoT(), dependentSubscription.Status.InstallPlanRef) require.Equal(GinkgoT(), dependentCSV.GetName(), dependentSubscription.Status.CurrentCSV) // Verify CSV is created - _, err = awaitCSV(crc, testNamespace, dependentCSV.GetName(), csvAnyChecker) + _, err = awaitCSV(crc, ns.GetName(), dependentCSV.GetName(), csvAnyChecker) require.NoError(GinkgoT(), err) // Update dependent subscription in catalog and wait for csv to update - updatedDependentCSV := newCSV(dependentPackageStable+"-v2", testNamespace, dependentPackageStable, semver.MustParse("0.1.1"), []apiextensions.CustomResourceDefinition{dependentCRD}, nil, nil) + updatedDependentCSV := newCSV(dependentPackageStable+"-v2", ns.GetName(), dependentPackageStable, semver.MustParse("0.1.1"), []apiextensions.CustomResourceDefinition{dependentCRD}, nil, nil) dependentManifests = []registry.PackageManifest{ { PackageName: dependentPackageName, @@ -766,20 +824,20 @@ var _ = Describe("Install Plan", func() { }, } - updateInternalCatalog(GinkgoT(), c, crc, dependentCatalogName, testNamespace, []apiextensions.CustomResourceDefinition{dependentCRD}, []operatorsv1alpha1.ClusterServiceVersion{dependentCSV, updatedDependentCSV}, dependentManifests) + updateInternalCatalog(GinkgoT(), c, crc, dependentCatalogName, ns.GetName(), []apiextensions.CustomResourceDefinition{dependentCRD}, []operatorsv1alpha1.ClusterServiceVersion{dependentCSV, updatedDependentCSV}, dependentManifests) // Wait for subscription to update - updatedDepSubscription, err := fetchSubscription(crc, testNamespace, strings.Join([]string{dependentPackageStable, dependentCatalogName, testNamespace}, "-"), subscriptionHasCurrentCSV(updatedDependentCSV.GetName())) + updatedDepSubscription, err := fetchSubscription(crc, ns.GetName(), strings.Join([]string{dependentPackageStable, dependentCatalogName, ns.GetName()}, "-"), subscriptionHasCurrentCSV(updatedDependentCSV.GetName())) require.NoError(GinkgoT(), err) // Verify installplan created and installed - fetchedUpdatedDepInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, updatedDepSubscription.Status.InstallPlanRef.Name, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) + fetchedUpdatedDepInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, updatedDepSubscription.Status.InstallPlanRef.Name, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) require.NoError(GinkgoT(), err) log(fmt.Sprintf("Install plan %s fetched with status %s", fetchedUpdatedDepInstallPlan.GetName(), fetchedUpdatedDepInstallPlan.Status.Phase)) require.NotEqual(GinkgoT(), fetchedInstallPlan.GetName(), fetchedUpdatedDepInstallPlan.GetName()) // Wait for csv to update - _, err = awaitCSV(crc, testNamespace, updatedDependentCSV.GetName(), csvAnyChecker) + _, err = awaitCSV(crc, ns.GetName(), updatedDependentCSV.GetName(), csvAnyChecker) require.NoError(GinkgoT(), err) }) @@ -822,24 +880,34 @@ var _ = Describe("Install Plan", func() { dependentCRD := newCRD(genName("ins-")) // Create new CSVs - mainStableCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{mainCRD}, []apiextensions.CustomResourceDefinition{dependentCRD}, nil) - mainBetaCSV := newCSV(mainPackageBeta, testNamespace, mainPackageStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{mainCRD}, []apiextensions.CustomResourceDefinition{dependentCRD}, nil) - dependentStableCSV := newCSV(dependentPackageStable, testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{dependentCRD}, nil, nil) - dependentBetaCSV := newCSV(dependentPackageBeta, testNamespace, dependentPackageStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{dependentCRD}, nil, nil) + mainStableCSV := newCSV(mainPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{mainCRD}, []apiextensions.CustomResourceDefinition{dependentCRD}, nil) + mainBetaCSV := newCSV(mainPackageBeta, ns.GetName(), mainPackageStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{mainCRD}, []apiextensions.CustomResourceDefinition{dependentCRD}, nil) + dependentStableCSV := newCSV(dependentPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{dependentCRD}, nil, nil) + dependentBetaCSV := newCSV(dependentPackageBeta, ns.GetName(), dependentPackageStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{dependentCRD}, nil, nil) + + // Defer CRD clean up + defer func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), mainCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), dependentCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + }() c := newKubeClient() crc := newCRClient() defer func() { - require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(testNamespace).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})) + require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(ns.GetName()).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{})) }() // Create the catalog source mainCatalogSourceName := genName("mock-ocs-main-" + strings.ToLower(K8sSafeCurrentTestDescription()) + "-") - _, cleanupCatalogSource := createInternalCatalogSource(c, crc, mainCatalogSourceName, testNamespace, mainManifests, []apiextensions.CustomResourceDefinition{dependentCRD, mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{dependentBetaCSV, dependentStableCSV, mainStableCSV, mainBetaCSV}) + _, cleanupCatalogSource := createInternalCatalogSource(c, crc, mainCatalogSourceName, ns.GetName(), mainManifests, []apiextensions.CustomResourceDefinition{dependentCRD, mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{dependentBetaCSV, dependentStableCSV, mainStableCSV, mainBetaCSV}) defer cleanupCatalogSource() // Attempt to get the catalog source before creating install plan(s) - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, testNamespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) expectedSteps := map[registry.ResourceKey]struct{}{ @@ -851,30 +919,30 @@ var _ = Describe("Install Plan", func() { cleanupCRD, err := createCRD(c, dependentCRD) require.NoError(GinkgoT(), err) defer cleanupCRD() - cleanupCSV, err := createCSV(c, crc, dependentBetaCSV, testNamespace, true, false) + cleanupCSV, err := createCSV(c, crc, dependentBetaCSV, ns.GetName(), true, false) require.NoError(GinkgoT(), err) defer cleanupCSV() GinkgoT().Log("Dependent CRD and preexisting CSV created") subscriptionName := genName("sub-nginx-") - subscriptionCleanup := createSubscriptionForCatalog(crc, testNamespace, subscriptionName, mainCatalogSourceName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogSourceName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) installPlanName := subscription.Status.InstallPlanRef.Name // Wait for InstallPlan to be status: Complete or Failed before checking resource presence - fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete, operatorsv1alpha1.InstallPlanPhaseFailed)) + fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete, operatorsv1alpha1.InstallPlanPhaseFailed)) require.NoError(GinkgoT(), err) GinkgoT().Logf("Install plan %s fetched with status %s", fetchedInstallPlan.GetName(), fetchedInstallPlan.Status.Phase) require.Equal(GinkgoT(), operatorsv1alpha1.InstallPlanPhaseComplete, fetchedInstallPlan.Status.Phase) // Fetch installplan again to check for unnecessary control loops - fetchedInstallPlan, err = fetchInstallPlan(GinkgoT(), crc, fetchedInstallPlan.GetName(), testNamespace, func(fip *operatorsv1alpha1.InstallPlan) bool { + fetchedInstallPlan, err = fetchInstallPlan(GinkgoT(), crc, fetchedInstallPlan.GetName(), ns.GetName(), func(fip *operatorsv1alpha1.InstallPlan) bool { Expect(equality.Semantic.DeepEqual(fetchedInstallPlan, fip)).Should(BeTrue(), diff.ObjectDiff(fetchedInstallPlan, fip)) return true }) @@ -900,6 +968,10 @@ var _ = Describe("Install Plan", func() { // Should have removed every matching step require.Equal(GinkgoT(), 0, len(expectedSteps), "Actual resource steps do not match expected") + + // Delete CRDs + Expect(client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), &mainCRD))).To(Succeed()) + Expect(client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), &dependentCRD))).To(Succeed()) }) }) @@ -916,7 +988,7 @@ var _ = Describe("Install Plan", func() { var max float64 = 256 var newMax float64 = 50 // generated outside of the test table so that the same naming can be used for both old and new CSVs - mainCRDPlural := "testcrd" + mainCRDPlural := genName("testcrd-") // excluded: new CRD, same version, same schema - won't trigger a CRD update tableEntries := []table.TableEntry{ @@ -1221,8 +1293,23 @@ var _ = Describe("Install Plan", func() { } // Create new CSVs - mainStableCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{*tt.oldCRD}, nil, nil) - mainBetaCSV := newCSV(mainPackageBeta, testNamespace, mainPackageStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{*tt.oldCRD}, nil, nil) + mainStableCSV := newCSV(mainPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{*tt.oldCRD}, nil, nil) + mainBetaCSV := newCSV(mainPackageBeta, ns.GetName(), mainPackageStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{*tt.oldCRD}, nil, nil) + + // Defer CRD clean up + defer func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), tt.oldCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), tt.newCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + if tt.intermediateCRD != nil { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), tt.intermediateCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + } + }() c := newKubeClient() crc := newCRClient() @@ -1233,7 +1320,7 @@ var _ = Describe("Install Plan", func() { "apiVersion": "cluster.com/v1alpha1", "kind": tt.oldCRD.Spec.Names.Kind, "metadata": map[string]interface{}{ - "namespace": testNamespace, + "namespace": ns.GetName(), "name": "my-cr-1", }, "spec": map[string]interface{}{ @@ -1244,18 +1331,18 @@ var _ = Describe("Install Plan", func() { // Create the catalog source mainCatalogSourceName := genName("mock-ocs-main-") - _, cleanupCatalogSource := createInternalCatalogSource(c, crc, mainCatalogSourceName, testNamespace, mainManifests, []apiextensions.CustomResourceDefinition{*tt.oldCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainStableCSV, mainBetaCSV}) + _, cleanupCatalogSource := createInternalCatalogSource(c, crc, mainCatalogSourceName, ns.GetName(), mainManifests, []apiextensions.CustomResourceDefinition{*tt.oldCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainStableCSV, mainBetaCSV}) defer cleanupCatalogSource() // Attempt to get the catalog source before creating install plan(s) - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, testNamespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-alpha-") - cleanupSubscription := createSubscriptionForCatalog(crc, testNamespace, subscriptionName, mainCatalogSourceName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + cleanupSubscription := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogSourceName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer cleanupSubscription() - subscription, err := fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -1263,7 +1350,7 @@ var _ = Describe("Install Plan", func() { // Wait for InstallPlan to be status: Complete or failed before checking resource presence completeOrFailedFunc := buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete, operatorsv1alpha1.InstallPlanPhaseFailed) - fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, testNamespace, completeOrFailedFunc) + fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, ns.GetName(), completeOrFailedFunc) require.NoError(GinkgoT(), err) GinkgoT().Logf("Install plan %s fetched with status %s", fetchedInstallPlan.GetName(), fetchedInstallPlan.Status.Phase) require.Equal(GinkgoT(), operatorsv1alpha1.InstallPlanPhaseComplete, fetchedInstallPlan.Status.Phase) @@ -1292,44 +1379,44 @@ var _ = Describe("Install Plan", func() { require.Equal(GinkgoT(), 0, len(expectedSteps), "Actual resource steps do not match expected") // Create initial CR - cleanupCR, err := createCR(c, existingCR, "cluster.com", "v1alpha1", testNamespace, tt.oldCRD.Spec.Names.Plural, "my-cr-1") + cleanupCR, err := createCR(c, existingCR, "cluster.com", "v1alpha1", ns.GetName(), tt.oldCRD.Spec.Names.Plural, "my-cr-1") require.NoError(GinkgoT(), err) defer cleanupCR() - updateInternalCatalog(GinkgoT(), c, crc, mainCatalogSourceName, testNamespace, []apiextensions.CustomResourceDefinition{*tt.newCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainStableCSV, mainBetaCSV}, mainManifests) + updateInternalCatalog(GinkgoT(), c, crc, mainCatalogSourceName, ns.GetName(), []apiextensions.CustomResourceDefinition{*tt.newCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainStableCSV, mainBetaCSV}, mainManifests) // Attempt to get the catalog source before creating install plan(s) - _, err = fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, testNamespace, catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) // Update the subscription resource to point to the beta CSV err = retry.RetryOnConflict(retry.DefaultBackoff, func() error { - subscription, err = fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err = fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) subscription.Spec.Channel = betaChannel - subscription, err = crc.OperatorsV1alpha1().Subscriptions(testNamespace).Update(context.TODO(), subscription, metav1.UpdateOptions{}) + subscription, err = crc.OperatorsV1alpha1().Subscriptions(ns.GetName()).Update(context.Background(), subscription, metav1.UpdateOptions{}) return err }) // Wait for subscription to have a new installplan - subscription, err = fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanDifferentChecker(fetchedInstallPlan.GetName())) + subscription, err = fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanDifferentChecker(fetchedInstallPlan.GetName())) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) installPlanName = subscription.Status.InstallPlanRef.Name // Wait for InstallPlan to be status: Complete or Failed before checking resource presence - fetchedInstallPlan, err = fetchInstallPlan(GinkgoT(), crc, installPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(tt.expectedPhase)) + fetchedInstallPlan, err = fetchInstallPlan(GinkgoT(), crc, installPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(tt.expectedPhase)) require.NoError(GinkgoT(), err) GinkgoT().Logf("Install plan %s fetched with status %s", fetchedInstallPlan.GetName(), fetchedInstallPlan.Status.Phase) require.Equal(GinkgoT(), tt.expectedPhase, fetchedInstallPlan.Status.Phase) // Ensure correct in-cluster resource(s) - fetchedCSV, err := fetchCSV(crc, mainBetaCSV.GetName(), testNamespace, csvAnyChecker) + fetchedCSV, err := fetchCSV(crc, mainBetaCSV.GetName(), ns.GetName(), csvAnyChecker) require.NoError(GinkgoT(), err) GinkgoT().Logf("All expected resources resolved %s", fetchedCSV.Status.Phase) @@ -1464,28 +1551,50 @@ var _ = Describe("Install Plan", func() { } // Create new CSVs - mainStableCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{*tt.oldCRD}, nil, nil) - mainBetaCSV := newCSV(mainPackageBeta, testNamespace, mainPackageStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{*tt.intermediateCRD}, nil, nil) - mainDeltaCSV := newCSV(mainPackageDelta, testNamespace, mainPackageBeta, semver.MustParse("0.3.0"), []apiextensions.CustomResourceDefinition{*tt.newCRD}, nil, nil) + mainStableCSV := newCSV(mainPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{*tt.oldCRD}, nil, nil) + mainBetaCSV := newCSV(mainPackageBeta, ns.GetName(), mainPackageStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{*tt.intermediateCRD}, nil, nil) + mainDeltaCSV := newCSV(mainPackageDelta, ns.GetName(), mainPackageBeta, semver.MustParse("0.3.0"), []apiextensions.CustomResourceDefinition{*tt.newCRD}, nil, nil) + + // Defer CRD clean up + defer func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), tt.oldCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), tt.newCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + if tt.intermediateCRD != nil { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), tt.intermediateCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + } + }() c := newKubeClient() crc := newCRClient() + // Defer crd clean up + defer func() { + Expect(client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), tt.newCRD))).To(Succeed()) + Expect(client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), tt.oldCRD))).To(Succeed()) + Expect(client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), tt.intermediateCRD))).To(Succeed()) + }() + // Create the catalog source mainCatalogSourceName := genName("mock-ocs-main-") - _, cleanupCatalogSource := createInternalCatalogSource(c, crc, mainCatalogSourceName, testNamespace, mainManifests, []apiextensions.CustomResourceDefinition{*tt.oldCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainStableCSV}) + _, cleanupCatalogSource := createInternalCatalogSource(c, crc, mainCatalogSourceName, ns.GetName(), mainManifests, []apiextensions.CustomResourceDefinition{*tt.oldCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainStableCSV}) defer cleanupCatalogSource() // Attempt to get the catalog source before creating install plan(s) - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, testNamespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-") // this subscription will be cleaned up below without the clean up function - createSubscriptionForCatalog(crc, testNamespace, subscriptionName, mainCatalogSourceName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogSourceName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) - subscription, err := fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) @@ -1493,7 +1602,7 @@ var _ = Describe("Install Plan", func() { // Wait for InstallPlan to be status: Complete or failed before checking resource presence completeOrFailedFunc := buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete, operatorsv1alpha1.InstallPlanPhaseFailed) - fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, testNamespace, completeOrFailedFunc) + fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, ns.GetName(), completeOrFailedFunc) require.NoError(GinkgoT(), err) GinkgoT().Logf("Install plan %s fetched with status %s", fetchedInstallPlan.GetName(), fetchedInstallPlan.Status.Phase) require.Equal(GinkgoT(), operatorsv1alpha1.InstallPlanPhaseComplete, fetchedInstallPlan.Status.Phase) @@ -1516,25 +1625,25 @@ var _ = Describe("Install Plan", func() { }, } - updateInternalCatalog(GinkgoT(), c, crc, mainCatalogSourceName, testNamespace, []apiextensions.CustomResourceDefinition{*tt.intermediateCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainStableCSV, mainBetaCSV}, mainManifests) + updateInternalCatalog(GinkgoT(), c, crc, mainCatalogSourceName, ns.GetName(), []apiextensions.CustomResourceDefinition{*tt.intermediateCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainStableCSV, mainBetaCSV}, mainManifests) // Attempt to get the catalog source before creating install plan(s) - _, err = fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, testNamespace, catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) - subscription, err = fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanDifferentChecker(installPlanName)) + subscription, err = fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanDifferentChecker(installPlanName)) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) installPlanName = subscription.Status.InstallPlanRef.Name // Wait for InstallPlan to be status: Complete or Failed before checking resource presence - fetchedInstallPlan, err = fetchInstallPlan(GinkgoT(), crc, installPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete, operatorsv1alpha1.InstallPlanPhaseFailed)) + fetchedInstallPlan, err = fetchInstallPlan(GinkgoT(), crc, installPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete, operatorsv1alpha1.InstallPlanPhaseFailed)) require.NoError(GinkgoT(), err) GinkgoT().Logf("Install plan %s fetched with status %s", fetchedInstallPlan.GetName(), fetchedInstallPlan.Status.Phase) require.Equal(GinkgoT(), tt.expectedPhase, fetchedInstallPlan.Status.Phase) // Ensure correct in-cluster resource(s) - fetchedCSV, err := fetchCSV(crc, mainBetaCSV.GetName(), testNamespace, csvSucceededChecker) + fetchedCSV, err := fetchCSV(crc, mainBetaCSV.GetName(), ns.GetName(), csvSucceededChecker) require.NoError(GinkgoT(), err) // Ensure CRD versions are accurate @@ -1556,25 +1665,25 @@ var _ = Describe("Install Plan", func() { }, } - updateInternalCatalog(GinkgoT(), c, crc, mainCatalogSourceName, testNamespace, []apiextensions.CustomResourceDefinition{*tt.newCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainStableCSV, mainBetaCSV, mainDeltaCSV}, mainManifests) + updateInternalCatalog(GinkgoT(), c, crc, mainCatalogSourceName, ns.GetName(), []apiextensions.CustomResourceDefinition{*tt.newCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainStableCSV, mainBetaCSV, mainDeltaCSV}, mainManifests) // Attempt to get the catalog source before creating install plan(s) - _, err = fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, testNamespace, catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) - subscription, err = fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanDifferentChecker(installPlanName)) + subscription, err = fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanDifferentChecker(installPlanName)) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) installPlanName = subscription.Status.InstallPlanRef.Name // Wait for InstallPlan to be status: Complete or Failed before checking resource presence - fetchedInstallPlan, err = fetchInstallPlan(GinkgoT(), crc, installPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete, operatorsv1alpha1.InstallPlanPhaseFailed)) + fetchedInstallPlan, err = fetchInstallPlan(GinkgoT(), crc, installPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete, operatorsv1alpha1.InstallPlanPhaseFailed)) require.NoError(GinkgoT(), err) GinkgoT().Logf("Install plan %s fetched with status %s", fetchedInstallPlan.GetName(), fetchedInstallPlan.Status.Phase) require.Equal(GinkgoT(), tt.expectedPhase, fetchedInstallPlan.Status.Phase) // Ensure correct in-cluster resource(s) - fetchedCSV, err = fetchCSV(crc, mainDeltaCSV.GetName(), testNamespace, csvSucceededChecker) + fetchedCSV, err = fetchCSV(crc, mainDeltaCSV.GetName(), ns.GetName(), csvSucceededChecker) require.NoError(GinkgoT(), err) // Ensure CRD versions are accurate @@ -1603,7 +1712,7 @@ var _ = Describe("Install Plan", func() { c := newKubeClient() crc := newCRClient() defer func() { - require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(testNamespace).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})) + require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(ns.GetName()).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{})) }() // Build initial catalog @@ -1671,7 +1780,7 @@ var _ = Describe("Install Plan", func() { // Create the catalog sources mainNamedStrategy := newNginxInstallStrategy(genName("dep-"), permissions, clusterPermissions) - mainCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), nil, nil, &mainNamedStrategy) + mainCSV := newCSV(mainPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), nil, nil, &mainNamedStrategy) mainCatalogName := genName("mock-ocs-amplify-") mainManifests := []registry.PackageManifest{ { @@ -1683,18 +1792,25 @@ var _ = Describe("Install Plan", func() { }, } - _, cleanupMainCatalogSource := createInternalCatalogSource(c, crc, mainCatalogName, testNamespace, mainManifests, []apiextensions.CustomResourceDefinition{mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV}) + // Defer CRD clean up + defer func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), mainCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + }() + + _, cleanupMainCatalogSource := createInternalCatalogSource(c, crc, mainCatalogName, ns.GetName(), mainManifests, []apiextensions.CustomResourceDefinition{mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV}) defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, testNamespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-update-perms1") - subscriptionCleanup := createSubscriptionForCatalog(crc, testNamespace, subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) require.NotNil(GinkgoT(), subscription.Status.InstallPlanRef) @@ -1703,13 +1819,13 @@ var _ = Describe("Install Plan", func() { installPlanName := subscription.Status.InstallPlanRef.Name // Wait for InstallPlan to be status: Complete before checking resource presence - fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) + fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), operatorsv1alpha1.InstallPlanPhaseComplete, fetchedInstallPlan.Status.Phase) // Verify CSV is created - _, err = awaitCSV(crc, testNamespace, mainCSV.GetName(), csvSucceededChecker) + _, err = awaitCSV(crc, ns.GetName(), mainCSV.GetName(), csvSucceededChecker) require.NoError(GinkgoT(), err) // Update CatalogSource with a new CSV with more permissions @@ -1750,7 +1866,7 @@ var _ = Describe("Install Plan", func() { // Create the catalog sources updatedNamedStrategy := newNginxInstallStrategy(genName("dep-"), updatedPermissions, updatedClusterPermissions) - updatedCSV := newCSV(mainPackageStable+"-next", testNamespace, mainCSV.GetName(), semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, &updatedNamedStrategy) + updatedCSV := newCSV(mainPackageStable+"-next", ns.GetName(), mainCSV.GetName(), semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, &updatedNamedStrategy) updatedManifests := []registry.PackageManifest{ { PackageName: mainPackageName, @@ -1762,20 +1878,20 @@ var _ = Describe("Install Plan", func() { } // Update catalog with updated CSV with more permissions - updateInternalCatalog(GinkgoT(), c, crc, mainCatalogName, testNamespace, []apiextensions.CustomResourceDefinition{mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV, updatedCSV}, updatedManifests) + updateInternalCatalog(GinkgoT(), c, crc, mainCatalogName, ns.GetName(), []apiextensions.CustomResourceDefinition{mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV, updatedCSV}, updatedManifests) - _, err = fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanDifferentChecker(fetchedInstallPlan.GetName())) + _, err = fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanDifferentChecker(fetchedInstallPlan.GetName())) require.NoError(GinkgoT(), err) updatedInstallPlanName := subscription.Status.InstallPlanRef.Name // Wait for InstallPlan to be status: Complete before checking resource presence - fetchedUpdatedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, updatedInstallPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) + fetchedUpdatedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, updatedInstallPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), operatorsv1alpha1.InstallPlanPhaseComplete, fetchedUpdatedInstallPlan.Status.Phase) // Wait for csv to update - _, err = awaitCSV(crc, testNamespace, updatedCSV.GetName(), csvSucceededChecker) + _, err = awaitCSV(crc, ns.GetName(), updatedCSV.GetName(), csvSucceededChecker) require.NoError(GinkgoT(), err) // If the CSV is succeeded, we successfully rolled out the RBAC changes @@ -1785,7 +1901,7 @@ var _ = Describe("Install Plan", func() { c := newKubeClient() crc := newCRClient() defer func() { - require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(testNamespace).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})) + require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(ns.GetName()).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{})) }() // Build initial catalog @@ -1864,7 +1980,7 @@ var _ = Describe("Install Plan", func() { // Create the catalog sources mainNamedStrategy := newNginxInstallStrategy(genName("dep-"), permissions, clusterPermissions) - mainCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), nil, nil, &mainNamedStrategy) + mainCSV := newCSV(mainPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), nil, nil, &mainNamedStrategy) mainCatalogName := genName("mock-ocs-main-update-perms1-") mainManifests := []registry.PackageManifest{ { @@ -1876,18 +1992,25 @@ var _ = Describe("Install Plan", func() { }, } - _, cleanupMainCatalogSource := createInternalCatalogSource(c, crc, mainCatalogName, testNamespace, mainManifests, []apiextensions.CustomResourceDefinition{mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV}) + // Defer CRD clean up + defer func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), mainCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + }() + + _, cleanupMainCatalogSource := createInternalCatalogSource(c, crc, mainCatalogName, ns.GetName(), mainManifests, []apiextensions.CustomResourceDefinition{mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV}) defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, testNamespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-update-perms1") - subscriptionCleanup := createSubscriptionForCatalog(crc, testNamespace, subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) require.NotNil(GinkgoT(), subscription.Status.InstallPlanRef) @@ -1896,13 +2019,13 @@ var _ = Describe("Install Plan", func() { installPlanName := subscription.Status.InstallPlanRef.Name // Wait for InstallPlan to be status: Complete before checking resource presence - fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) + fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), operatorsv1alpha1.InstallPlanPhaseComplete, fetchedInstallPlan.Status.Phase) // Verify CSV is created - _, err = awaitCSV(crc, testNamespace, mainCSV.GetName(), csvSucceededChecker) + _, err = awaitCSV(crc, ns.GetName(), mainCSV.GetName(), csvSucceededChecker) require.NoError(GinkgoT(), err) // Update CatalogSource with a new CSV with more permissions @@ -1931,12 +2054,12 @@ var _ = Describe("Install Plan", func() { }, } - oldSecrets, err := c.KubernetesInterface().CoreV1().Secrets(testNamespace).List(context.TODO(), metav1.ListOptions{}) + oldSecrets, err := c.KubernetesInterface().CoreV1().Secrets(ns.GetName()).List(context.Background(), metav1.ListOptions{}) require.NoError(GinkgoT(), err, "error listing secrets") // Create the catalog sources updatedNamedStrategy := newNginxInstallStrategy(genName("dep-"), updatedPermissions, updatedClusterPermissions) - updatedCSV := newCSV(mainPackageStable+"-next", testNamespace, mainCSV.GetName(), semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, &updatedNamedStrategy) + updatedCSV := newCSV(mainPackageStable+"-next", ns.GetName(), mainCSV.GetName(), semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, &updatedNamedStrategy) updatedManifests := []registry.PackageManifest{ { PackageName: mainPackageName, @@ -1948,24 +2071,24 @@ var _ = Describe("Install Plan", func() { } // Update catalog with updated CSV with more permissions - updateInternalCatalog(GinkgoT(), c, crc, mainCatalogName, testNamespace, []apiextensions.CustomResourceDefinition{mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV, updatedCSV}, updatedManifests) + updateInternalCatalog(GinkgoT(), c, crc, mainCatalogName, ns.GetName(), []apiextensions.CustomResourceDefinition{mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV, updatedCSV}, updatedManifests) // Wait for subscription to update its status - _, err = fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanDifferentChecker(fetchedInstallPlan.GetName())) + _, err = fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanDifferentChecker(fetchedInstallPlan.GetName())) require.NoError(GinkgoT(), err) updatedInstallPlanName := subscription.Status.InstallPlanRef.Name // Wait for InstallPlan to be status: Complete before checking resource presence - fetchedUpdatedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, updatedInstallPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) + fetchedUpdatedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, updatedInstallPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), operatorsv1alpha1.InstallPlanPhaseComplete, fetchedUpdatedInstallPlan.Status.Phase) // Wait for csv to update - _, err = awaitCSV(crc, testNamespace, updatedCSV.GetName(), csvSucceededChecker) + _, err = awaitCSV(crc, ns.GetName(), updatedCSV.GetName(), csvSucceededChecker) require.NoError(GinkgoT(), err) - newSecrets, err := c.KubernetesInterface().CoreV1().Secrets(testNamespace).List(context.TODO(), metav1.ListOptions{}) + newSecrets, err := c.KubernetesInterface().CoreV1().Secrets(ns.GetName()).List(context.Background(), metav1.ListOptions{}) require.NoError(GinkgoT(), err, "error listing secrets") // Assert that the number of secrets is not increased from updating service account as part of the install plan, @@ -1976,9 +2099,9 @@ var _ = Describe("Install Plan", func() { // Wait for ServiceAccount to not have access anymore err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { - res, err := c.KubernetesInterface().AuthorizationV1().SubjectAccessReviews().Create(context.TODO(), &authorizationv1.SubjectAccessReview{ + res, err := c.KubernetesInterface().AuthorizationV1().SubjectAccessReviews().Create(context.Background(), &authorizationv1.SubjectAccessReview{ Spec: authorizationv1.SubjectAccessReviewSpec{ - User: "system:serviceaccount:" + testNamespace + ":" + serviceAccountName, + User: "system:serviceaccount:" + ns.GetName() + ":" + serviceAccountName, ResourceAttributes: &authorizationv1.ResourceAttributes{ Group: "cluster.com", Version: "v1alpha1", @@ -1998,14 +2121,14 @@ var _ = Describe("Install Plan", func() { // should not be allowed return !res.Status.Allowed, nil }) - }) + It("StopOnCSVModifications", func() { c := newKubeClient() crc := newCRClient() defer func() { - require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(testNamespace).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})) + require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(ns.GetName()).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{})) }() // Build initial catalog @@ -2075,7 +2198,7 @@ var _ = Describe("Install Plan", func() { // Create the catalog sources deploymentName := genName("dep-") mainNamedStrategy := newNginxInstallStrategy(deploymentName, permissions, clusterPermissions) - mainCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), nil, nil, &mainNamedStrategy) + mainCSV := newCSV(mainPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), nil, nil, &mainNamedStrategy) mainCatalogName := genName("mock-ocs-stomper-") mainManifests := []registry.PackageManifest{ { @@ -2086,18 +2209,26 @@ var _ = Describe("Install Plan", func() { DefaultChannelName: stableChannel, }, } - _, cleanupMainCatalogSource := createInternalCatalogSource(c, crc, mainCatalogName, testNamespace, mainManifests, []apiextensions.CustomResourceDefinition{mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV}) + + // Defer CRD clean up + defer func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), mainCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + }() + + _, cleanupMainCatalogSource := createInternalCatalogSource(c, crc, mainCatalogName, ns.GetName(), mainManifests, []apiextensions.CustomResourceDefinition{mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV}) defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, testNamespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-stompy-") - subscriptionCleanup := createSubscriptionForCatalog(crc, testNamespace, subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) require.NotNil(GinkgoT(), subscription.Status.InstallPlanRef) @@ -2106,13 +2237,13 @@ var _ = Describe("Install Plan", func() { installPlanName := subscription.Status.InstallPlanRef.Name // Wait for InstallPlan to be status: Complete before checking resource presence - fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) + fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), operatorsv1alpha1.InstallPlanPhaseComplete, fetchedInstallPlan.Status.Phase) // Verify CSV is created - csv, err := awaitCSV(crc, testNamespace, mainCSV.GetName(), csvSucceededChecker) + csv, err := awaitCSV(crc, ns.GetName(), mainCSV.GetName(), csvSucceededChecker) require.NoError(GinkgoT(), err) addedEnvVar := corev1.EnvVar{Name: "EXAMPLE", Value: "value"} @@ -2149,16 +2280,16 @@ var _ = Describe("Install Plan", func() { StrategyName: operatorsv1alpha1.InstallStrategyNameDeployment, StrategySpec: modifiedDetails, } - _, err = crc.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).Update(context.TODO(), csv, metav1.UpdateOptions{}) + _, err = crc.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).Update(context.Background(), csv, metav1.UpdateOptions{}) require.NoError(GinkgoT(), err) // Wait for csv to update - _, err = awaitCSV(crc, testNamespace, csv.GetName(), csvSucceededChecker) + _, err = awaitCSV(crc, ns.GetName(), csv.GetName(), csvSucceededChecker) require.NoError(GinkgoT(), err) // Should have the updated env var err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { - dep, err := c.GetDeployment(testNamespace, deploymentName) + dep, err := c.GetDeployment(ns.GetName(), deploymentName) if err != nil { return false, nil } @@ -2176,7 +2307,7 @@ var _ = Describe("Install Plan", func() { // Create the catalog sources // Updated csv has the same deployment strategy as main - updatedCSV := newCSV(mainPackageStable+"-next", testNamespace, mainCSV.GetName(), semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, &mainNamedStrategy) + updatedCSV := newCSV(mainPackageStable+"-next", ns.GetName(), mainCSV.GetName(), semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, &mainNamedStrategy) updatedManifests := []registry.PackageManifest{ { PackageName: mainPackageName, @@ -2188,24 +2319,24 @@ var _ = Describe("Install Plan", func() { } // Update catalog with updated CSV with more permissions - updateInternalCatalog(GinkgoT(), c, crc, mainCatalogName, testNamespace, []apiextensions.CustomResourceDefinition{mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV, updatedCSV}, updatedManifests) + updateInternalCatalog(GinkgoT(), c, crc, mainCatalogName, ns.GetName(), []apiextensions.CustomResourceDefinition{mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV, updatedCSV}, updatedManifests) - _, err = fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanDifferentChecker(fetchedInstallPlan.GetName())) + _, err = fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanDifferentChecker(fetchedInstallPlan.GetName())) require.NoError(GinkgoT(), err) updatedInstallPlanName := subscription.Status.InstallPlanRef.Name // Wait for InstallPlan to be status: Complete before checking resource presence - fetchedUpdatedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, updatedInstallPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) + fetchedUpdatedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, updatedInstallPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), operatorsv1alpha1.InstallPlanPhaseComplete, fetchedUpdatedInstallPlan.Status.Phase) // Wait for csv to update - _, err = awaitCSV(crc, testNamespace, updatedCSV.GetName(), csvSucceededChecker) + _, err = awaitCSV(crc, ns.GetName(), updatedCSV.GetName(), csvSucceededChecker) require.NoError(GinkgoT(), err) // Should have created deployment and stomped on the env changes - updatedDep, err := c.GetDeployment(testNamespace, deploymentName) + updatedDep, err := c.GetDeployment(ns.GetName(), deploymentName) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), updatedDep) @@ -2214,6 +2345,7 @@ var _ = Describe("Install Plan", func() { require.False(GinkgoT(), envVar == addedEnvVar) } }) + It("UpdateSingleExistingCRDOwner", func() { mainPackageName := genName("nginx-update-") @@ -2294,13 +2426,23 @@ var _ = Describe("Install Plan", func() { }, } - mainCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, nil) - betaCSV := newCSV(mainPackageBeta, testNamespace, mainPackageStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{updatedCRD}, nil, nil) + mainCSV := newCSV(mainPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, nil) + betaCSV := newCSV(mainPackageBeta, ns.GetName(), mainPackageStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{updatedCRD}, nil, nil) + + // Defer CRD clean up + defer func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), mainCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), updatedCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + }() c := newKubeClient() crc := newCRClient() defer func() { - require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(testNamespace).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})) + require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(ns.GetName()).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{})) }() mainCatalogName := genName("mock-ocs-main-update-") @@ -2317,17 +2459,17 @@ var _ = Describe("Install Plan", func() { } // Create the catalog sources - _, cleanupMainCatalogSource := createInternalCatalogSource(c, crc, mainCatalogName, testNamespace, mainManifests, []apiextensions.CustomResourceDefinition{mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV}) + _, cleanupMainCatalogSource := createInternalCatalogSource(c, crc, mainCatalogName, ns.GetName(), mainManifests, []apiextensions.CustomResourceDefinition{mainCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV}) defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, testNamespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-update-") - createSubscriptionForCatalog(crc, testNamespace, subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) - subscription, err := fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) require.NotNil(GinkgoT(), subscription.Status.InstallPlanRef) @@ -2336,20 +2478,20 @@ var _ = Describe("Install Plan", func() { installPlanName := subscription.Status.InstallPlanRef.Name // Wait for InstallPlan to be status: Complete before checking resource presence - fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) + fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), operatorsv1alpha1.InstallPlanPhaseComplete, fetchedInstallPlan.Status.Phase) // Fetch installplan again to check for unnecessary control loops - fetchedInstallPlan, err = fetchInstallPlan(GinkgoT(), crc, fetchedInstallPlan.GetName(), testNamespace, func(fip *operatorsv1alpha1.InstallPlan) bool { + fetchedInstallPlan, err = fetchInstallPlan(GinkgoT(), crc, fetchedInstallPlan.GetName(), ns.GetName(), func(fip *operatorsv1alpha1.InstallPlan) bool { Expect(equality.Semantic.DeepEqual(fetchedInstallPlan, fip)).Should(BeTrue(), diff.ObjectDiff(fetchedInstallPlan, fip)) return true }) require.NoError(GinkgoT(), err) // Verify CSV is created - _, err = awaitCSV(crc, testNamespace, mainCSV.GetName(), csvAnyChecker) + _, err = awaitCSV(crc, ns.GetName(), mainCSV.GetName(), csvAnyChecker) require.NoError(GinkgoT(), err) mainManifests = []registry.PackageManifest{ @@ -2362,22 +2504,22 @@ var _ = Describe("Install Plan", func() { }, } - updateInternalCatalog(GinkgoT(), c, crc, mainCatalogName, testNamespace, []apiextensions.CustomResourceDefinition{updatedCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV, betaCSV}, mainManifests) + updateInternalCatalog(GinkgoT(), c, crc, mainCatalogName, ns.GetName(), []apiextensions.CustomResourceDefinition{updatedCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV, betaCSV}, mainManifests) // Wait for subscription to update - updatedSubscription, err := fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanDifferentChecker(fetchedInstallPlan.GetName())) + updatedSubscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanDifferentChecker(fetchedInstallPlan.GetName())) require.NoError(GinkgoT(), err) // Verify installplan created and installed - fetchedUpdatedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, updatedSubscription.Status.InstallPlanRef.Name, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) + fetchedUpdatedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, updatedSubscription.Status.InstallPlanRef.Name, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) require.NoError(GinkgoT(), err) require.NotEqual(GinkgoT(), fetchedInstallPlan.GetName(), fetchedUpdatedInstallPlan.GetName()) // Wait for csv to update - _, err = awaitCSV(crc, testNamespace, betaCSV.GetName(), csvAnyChecker) + _, err = awaitCSV(crc, ns.GetName(), betaCSV.GetName(), csvAnyChecker) require.NoError(GinkgoT(), err) // Get the CRD to see if it is updated - fetchedCRD, err := c.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), crdName, metav1.GetOptions{}) + fetchedCRD, err := c.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Get(context.Background(), crdName, metav1.GetOptions{}) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), len(fetchedCRD.Spec.Versions), len(updatedCRD.Spec.Versions), "The CRD versions counts don't match") @@ -2401,12 +2543,13 @@ var _ = Describe("Install Plan", func() { require.True(GinkgoT(), ok, "couldn't find %v in fetched CRD versions: %#v", key, fetchedCRDVersions) } }) + It("UpdatePreexistingCRDFailed", func() { c := newKubeClient() crc := newCRClient() defer func() { - require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(testNamespace).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})) + require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(ns.GetName()).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{})) }() mainPackageName := genName("nginx-update2-") @@ -2501,7 +2644,7 @@ var _ = Describe("Install Plan", func() { require.NoError(GinkgoT(), err) defer cleanupCRD() - mainCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), nil, nil, nil) + mainCSV := newCSV(mainPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), nil, nil, nil) mainCatalogName := genName("mock-ocs-main-update2-") @@ -2517,18 +2660,18 @@ var _ = Describe("Install Plan", func() { } // Create the catalog sources - _, cleanupMainCatalogSource := createInternalCatalogSource(c, crc, mainCatalogName, testNamespace, mainManifests, []apiextensions.CustomResourceDefinition{updatedCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV}) + _, cleanupMainCatalogSource := createInternalCatalogSource(c, crc, mainCatalogName, ns.GetName(), mainManifests, []apiextensions.CustomResourceDefinition{updatedCRD}, []operatorsv1alpha1.ClusterServiceVersion{mainCSV}) defer cleanupMainCatalogSource() // Attempt to get the catalog source before creating install plan - _, err = fetchCatalogSourceOnStatus(crc, mainCatalogName, testNamespace, catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, mainCatalogName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-update2-") - subscriptionCleanup := createSubscriptionForCatalog(crc, testNamespace, subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogName, mainPackageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) require.NotNil(GinkgoT(), subscription.Status.InstallPlanRef) @@ -2537,24 +2680,24 @@ var _ = Describe("Install Plan", func() { installPlanName := subscription.Status.InstallPlanRef.Name // Wait for InstallPlan to be status: Complete before checking resource presence - fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) + fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete)) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), operatorsv1alpha1.InstallPlanPhaseComplete, fetchedInstallPlan.Status.Phase) // Fetch installplan again to check for unnecessary control loops - fetchedInstallPlan, err = fetchInstallPlan(GinkgoT(), crc, fetchedInstallPlan.GetName(), testNamespace, func(fip *operatorsv1alpha1.InstallPlan) bool { + fetchedInstallPlan, err = fetchInstallPlan(GinkgoT(), crc, fetchedInstallPlan.GetName(), ns.GetName(), func(fip *operatorsv1alpha1.InstallPlan) bool { Expect(equality.Semantic.DeepEqual(fetchedInstallPlan, fip)).Should(BeTrue(), diff.ObjectDiff(fetchedInstallPlan, fip)) return true }) require.NoError(GinkgoT(), err) // Verify CSV is created - _, err = awaitCSV(crc, testNamespace, mainCSV.GetName(), csvAnyChecker) + _, err = awaitCSV(crc, ns.GetName(), mainCSV.GetName(), csvAnyChecker) require.NoError(GinkgoT(), err) // Get the CRD to see if it is updated - fetchedCRD, err := c.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), crdName, metav1.GetOptions{}) + fetchedCRD, err := c.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Get(context.Background(), crdName, metav1.GetOptions{}) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), len(fetchedCRD.Spec.Versions), len(mainCRD.Spec.Versions), "The CRD versions counts don't match") @@ -2578,9 +2721,6 @@ var _ = Describe("Install Plan", func() { require.True(GinkgoT(), ok, "couldn't find %v in fetched CRD versions: %#v", key, fetchedCRDVersions) } }) - AfterEach(func() { - - }) }) // This It spec creates an InstallPlan with a CSV containing a set of permissions to be resolved. @@ -2608,6 +2748,13 @@ var _ = Describe("Install Plan", func() { crdPlural := genName("ins") crd := newCRD(crdPlural) + // Defer CRD clean up + defer func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), crd.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + }() + // Generate permissions serviceAccountName := genName("nginx-sa") permissions := []operatorsv1alpha1.StrategyDeploymentPermissions{ @@ -2647,35 +2794,35 @@ var _ = Describe("Install Plan", func() { namedStrategy := newNginxInstallStrategy(genName("dep-"), permissions, clusterPermissions) // Create new CSVs - stableCSV := newCSV(stableCSVName, testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd}, nil, &namedStrategy) + stableCSV := newCSV(stableCSVName, ns.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd}, nil, &namedStrategy) c := newKubeClient() crc := newCRClient() defer func() { - require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(testNamespace).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})) + require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(ns.GetName()).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{})) }() // Create CatalogSource mainCatalogSourceName := genName("nginx-catalog") - _, cleanupCatalogSource := createInternalCatalogSource(c, crc, mainCatalogSourceName, testNamespace, manifests, []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{stableCSV}) + _, cleanupCatalogSource := createInternalCatalogSource(c, crc, mainCatalogSourceName, ns.GetName(), manifests, []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{stableCSV}) defer cleanupCatalogSource() // Attempt to get CatalogSource - _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, testNamespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, mainCatalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-") - subscriptionCleanup := createSubscriptionForCatalog(crc, testNamespace, subscriptionName, mainCatalogSourceName, packageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + subscriptionCleanup := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, mainCatalogSourceName, packageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer subscriptionCleanup() - subscription, err := fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) installPlanName := subscription.Status.InstallPlanRef.Name // Attempt to get InstallPlan - fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseFailed, operatorsv1alpha1.InstallPlanPhaseComplete)) + fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseFailed, operatorsv1alpha1.InstallPlanPhaseComplete)) require.NoError(GinkgoT(), err) require.NotEqual(GinkgoT(), operatorsv1alpha1.InstallPlanPhaseFailed, fetchedInstallPlan.Status.Phase, "InstallPlan failed") @@ -2712,7 +2859,7 @@ var _ = Describe("Install Plan", func() { err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { _, err = c.GetClusterRole(step.Resource.Name) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return false, nil } return false, err @@ -2725,7 +2872,7 @@ var _ = Describe("Install Plan", func() { err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { _, err = c.GetClusterRoleBinding(step.Resource.Name) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return false, nil } return false, err @@ -2740,23 +2887,23 @@ var _ = Describe("Install Plan", func() { require.Equal(GinkgoT(), 0, len(expectedSteps), "Actual resource steps do not match expected: %#v", expectedSteps) // the test from here out verifies created RBAC is removed after CSV deletion - createdClusterRoles, err := c.KubernetesInterface().RbacV1().ClusterRoles().List(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("%v=%v", ownerutil.OwnerKey, stableCSVName)}) + createdClusterRoles, err := c.KubernetesInterface().RbacV1().ClusterRoles().List(context.Background(), metav1.ListOptions{LabelSelector: fmt.Sprintf("%v=%v", ownerutil.OwnerKey, stableCSVName)}) createdClusterRoleNames := map[string]struct{}{} for _, role := range createdClusterRoles.Items { createdClusterRoleNames[role.GetName()] = struct{}{} GinkgoT().Logf("Monitoring cluster role %v", role.GetName()) } - createdClusterRoleBindings, err := c.KubernetesInterface().RbacV1().ClusterRoleBindings().List(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("%v=%v", ownerutil.OwnerKey, stableCSVName)}) + createdClusterRoleBindings, err := c.KubernetesInterface().RbacV1().ClusterRoleBindings().List(context.Background(), metav1.ListOptions{LabelSelector: fmt.Sprintf("%v=%v", ownerutil.OwnerKey, stableCSVName)}) createdClusterRoleBindingNames := map[string]struct{}{} for _, binding := range createdClusterRoleBindings.Items { createdClusterRoleBindingNames[binding.GetName()] = struct{}{} GinkgoT().Logf("Monitoring cluster role binding %v", binding.GetName()) } - crWatcher, err := c.KubernetesInterface().RbacV1().ClusterRoles().Watch(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("%v=%v", ownerutil.OwnerKey, stableCSVName)}) + crWatcher, err := c.KubernetesInterface().RbacV1().ClusterRoles().Watch(context.Background(), metav1.ListOptions{LabelSelector: fmt.Sprintf("%v=%v", ownerutil.OwnerKey, stableCSVName)}) require.NoError(GinkgoT(), err) - crbWatcher, err := c.KubernetesInterface().RbacV1().ClusterRoleBindings().Watch(context.TODO(), metav1.ListOptions{LabelSelector: fmt.Sprintf("%v=%v", ownerutil.OwnerKey, stableCSVName)}) + crbWatcher, err := c.KubernetesInterface().RbacV1().ClusterRoleBindings().Watch(context.Background(), metav1.ListOptions{LabelSelector: fmt.Sprintf("%v=%v", ownerutil.OwnerKey, stableCSVName)}) require.NoError(GinkgoT(), err) done := make(chan struct{}) @@ -2803,8 +2950,8 @@ var _ = Describe("Install Plan", func() { } } }() - GinkgoT().Logf("Deleting CSV '%v' in namespace %v", stableCSVName, testNamespace) - require.NoError(GinkgoT(), crc.OperatorsV1alpha1().ClusterServiceVersions(testNamespace).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})) + GinkgoT().Logf("Deleting CSV '%v' in namespace %v", stableCSVName, ns.GetName()) + require.NoError(GinkgoT(), crc.OperatorsV1alpha1().ClusterServiceVersions(ns.GetName()).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{})) select { case <-done: break @@ -2816,11 +2963,11 @@ var _ = Describe("Install Plan", func() { require.Emptyf(GinkgoT(), createdClusterRoleBindingNames, "unexpected cluster role binding remain: %v", createdClusterRoleBindingNames) Eventually(func() error { - _, err := c.GetServiceAccount(testNamespace, serviceAccountName) + _, err := c.GetServiceAccount(ns.GetName(), serviceAccountName) if err == nil { - return fmt.Errorf("The %v/%v ServiceAccount should have been deleted", testNamespace, serviceAccountName) + return fmt.Errorf("The %v/%v ServiceAccount should have been deleted", ns.GetName(), serviceAccountName) } - if !k8serrors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return err } return nil @@ -2879,11 +3026,18 @@ var _ = Describe("Install Plan", func() { }, } + // Defer CRD clean up + defer func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), crd.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + }() + // Create CSV packageName := genName("nginx-") stableChannel := "stable" packageNameStable := packageName + "-" + stableChannel - csv := newCSV(packageNameStable, testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd}, nil, nil) + csv := newCSV(packageNameStable, ns.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd}, nil, nil) // Create PackageManifests manifests := []registry.PackageManifest{ @@ -2899,26 +3053,27 @@ var _ = Describe("Install Plan", func() { // Create the CatalogSource c := newKubeClient() crc := newCRClient() + catalogSourceName := genName("mock-nginx-") - _, cleanupCatalogSource := createInternalCatalogSource(c, crc, catalogSourceName, testNamespace, manifests, []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{csv}) + _, cleanupCatalogSource := createInternalCatalogSource(c, crc, catalogSourceName, ns.GetName(), manifests, []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{csv}) defer cleanupCatalogSource() // Attempt to get the catalog source before creating install plan - _, err := fetchCatalogSourceOnStatus(crc, catalogSourceName, testNamespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, catalogSourceName, ns.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) subscriptionName := genName("sub-nginx-") - cleanupSubscription := createSubscriptionForCatalog(crc, testNamespace, subscriptionName, catalogSourceName, packageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + cleanupSubscription := createSubscriptionForCatalog(crc, ns.GetName(), subscriptionName, catalogSourceName, packageName, stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) defer cleanupSubscription() - subscription, err := fetchSubscription(crc, testNamespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crc, ns.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) installPlanName := subscription.Status.InstallPlanRef.Name // Wait for InstallPlan to be status: Complete before checking resource presence - fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, testNamespace, buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete, operatorsv1alpha1.InstallPlanPhaseFailed)) + fetchedInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, installPlanName, ns.GetName(), buildInstallPlanPhaseCheckFunc(operatorsv1alpha1.InstallPlanPhaseComplete, operatorsv1alpha1.InstallPlanPhaseFailed)) require.NoError(GinkgoT(), err) GinkgoT().Logf("Install plan %s fetched with status %s", fetchedInstallPlan.GetName(), fetchedInstallPlan.Status.Phase) @@ -2930,7 +3085,7 @@ var _ = Describe("Install Plan", func() { c := newKubeClient() crc := newCRClient() - ns, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{ + ns, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.Background(), &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: genName("ns-"), }, @@ -2939,12 +3094,12 @@ var _ = Describe("Install Plan", func() { og := &operatorsv1.OperatorGroup{} og.SetName("og") - _, err = crc.OperatorsV1().OperatorGroups(ns.GetName()).Create(context.TODO(), og, metav1.CreateOptions{}) + _, err = crc.OperatorsV1().OperatorGroups(ns.GetName()).Create(context.Background(), og, metav1.CreateOptions{}) require.NoError(GinkgoT(), err) deleteOpts := &metav1.DeleteOptions{} defer func() { - require.NoError(GinkgoT(), c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), ns.GetName(), *deleteOpts)) + require.NoError(GinkgoT(), c.KubernetesInterface().CoreV1().Namespaces().Delete(context.Background(), ns.GetName(), *deleteOpts)) }() catsrc := &operatorsv1alpha1.CatalogSource{ @@ -2958,8 +3113,13 @@ var _ = Describe("Install Plan", func() { SourceType: operatorsv1alpha1.SourceTypeGrpc, }, } - catsrc, err = crc.OperatorsV1alpha1().CatalogSources(catsrc.GetNamespace()).Create(context.TODO(), catsrc, metav1.CreateOptions{}) + catsrc, err = crc.OperatorsV1alpha1().CatalogSources(catsrc.GetNamespace()).Create(context.Background(), catsrc, metav1.CreateOptions{}) require.NoError(GinkgoT(), err) + defer func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), catsrc)) + }).Should(Succeed()) + }() // Wait for the CatalogSource to be ready catsrc, err = fetchCatalogSourceOnStatus(crc, catsrc.GetName(), catsrc.GetNamespace(), catalogSourceRegistryPodSynced) @@ -2967,7 +3127,8 @@ var _ = Describe("Install Plan", func() { // Generate a Subscription subName := genName("kiali-") - createSubscriptionForCatalog(crc, catsrc.GetNamespace(), subName, catsrc.GetName(), "kiali", stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + cleanUpSubscriptionFn := createSubscriptionForCatalog(crc, catsrc.GetNamespace(), subName, catsrc.GetName(), "kiali", stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + defer cleanUpSubscriptionFn() sub, err := fetchSubscription(crc, catsrc.GetNamespace(), subName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) @@ -3027,16 +3188,16 @@ var _ = Describe("Install Plan", func() { crc := newCRClient() // Create a namespace an OperatorGroup - ns, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), ns, metav1.CreateOptions{}) + ns, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.Background(), ns, metav1.CreateOptions{}) require.NoError(GinkgoT(), err) deleteOpts := &metav1.DeleteOptions{} defer func() { - require.NoError(GinkgoT(), c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), ns.GetName(), *deleteOpts)) + require.NoError(GinkgoT(), c.KubernetesInterface().CoreV1().Namespaces().Delete(context.Background(), ns.GetName(), *deleteOpts)) }() og := &operatorsv1.OperatorGroup{} og.SetName("og") - _, err = crc.OperatorsV1().OperatorGroups(ns.GetName()).Create(context.TODO(), og, metav1.CreateOptions{}) + _, err = crc.OperatorsV1().OperatorGroups(ns.GetName()).Create(context.Background(), og, metav1.CreateOptions{}) require.NoError(GinkgoT(), err) mainPackageName := genName("nginx-") @@ -3052,7 +3213,7 @@ var _ = Describe("Install Plan", func() { dependentCSV := newCSV(dependentPackageStable, ns.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{dependentCRD}, nil, nil) defer func() { - require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(ns.GetName()).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})) + require.NoError(GinkgoT(), crc.OperatorsV1alpha1().Subscriptions(ns.GetName()).DeleteCollection(context.Background(), metav1.DeleteOptions{}, metav1.ListOptions{})) }() dependentCatalogName := genName("mock-ocs-dependent-") @@ -3079,6 +3240,13 @@ var _ = Describe("Install Plan", func() { }, } + // Defer CRD clean up + defer func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), dependentCRD.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + }() + // Create the dependent catalog source _, cleanupDependentCatalogSource := createInternalCatalogSource(c, crc, dependentCatalogName, ns.GetName(), dependentManifests, []apiextensions.CustomResourceDefinition{dependentCRD}, []operatorsv1alpha1.ClusterServiceVersion{dependentCSV}) defer cleanupDependentCatalogSource() @@ -3106,7 +3274,7 @@ var _ = Describe("Install Plan", func() { } addressSource.SetName(genName("alt-dep-")) - _, err := crc.OperatorsV1alpha1().CatalogSources(ns.GetName()).Create(context.TODO(), addressSource, metav1.CreateOptions{}) + _, err := crc.OperatorsV1alpha1().CatalogSources(ns.GetName()).Create(context.Background(), addressSource, metav1.CreateOptions{}) require.NoError(GinkgoT(), err) // Attempt to get the catalog source before creating install plan @@ -3148,11 +3316,11 @@ var _ = Describe("Install Plan", func() { // Make sure to clean up the installed CRD defer func() { - require.NoError(GinkgoT(), c.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), dependentCRD.GetName(), *deleteOpts)) + require.NoError(GinkgoT(), c.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), dependentCRD.GetName(), *deleteOpts)) }() // ensure there is only one installplan - ips, err := crc.OperatorsV1alpha1().InstallPlans(ns.GetName()).List(context.TODO(), metav1.ListOptions{}) + ips, err := crc.OperatorsV1alpha1().InstallPlans(ns.GetName()).List(context.Background(), metav1.ListOptions{}) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), 1, len(ips.Items), "If this test fails it should be taken seriously and not treated as a flake. \n%v", ips.Items) }) @@ -3180,17 +3348,24 @@ var _ = Describe("Install Plan", func() { // Create InstallPlan installPlanName = "ip" ip := newInstallPlanWithDummySteps(installPlanName, ns.GetName(), operatorsv1alpha1.InstallPlanPhaseInstalling) - outIP, err := crc.OperatorsV1alpha1().InstallPlans(ns.GetName()).Create(context.TODO(), ip, metav1.CreateOptions{}) + outIP, err := crc.OperatorsV1alpha1().InstallPlans(ns.GetName()).Create(context.Background(), ip, metav1.CreateOptions{}) Expect(err).NotTo(HaveOccurred()) Expect(outIP).NotTo(BeNil()) // The status gets ignored on create so we need to update it else the InstallPlan sync ignores // InstallPlans without any steps or bundle lookups outIP.Status = ip.Status - _, err = crc.OperatorsV1alpha1().InstallPlans(ns.GetName()).UpdateStatus(context.TODO(), outIP, metav1.UpdateOptions{}) + _, err = crc.OperatorsV1alpha1().InstallPlans(ns.GetName()).UpdateStatus(context.Background(), outIP, metav1.UpdateOptions{}) Expect(err).NotTo(HaveOccurred()) }) + AfterEach(func() { + err := crc.OperatorsV1alpha1().InstallPlans(ns.GetName()).Delete(context.Background(), installPlanName, metav1.DeleteOptions{}) + Expect(err).NotTo(HaveOccurred()) + err = c.KubernetesInterface().CoreV1().Namespaces().Delete(context.Background(), ns.GetName(), metav1.DeleteOptions{}) + Expect(err).ToNot(HaveOccurred()) + }) + // issue: https://github.com/operator-framework/operator-lifecycle-manager/issues/2636 It("[FLAKE] should clear up the condition in the InstallPlan status that contains an error message when a valid OperatorGroup is created", func() { @@ -3249,14 +3424,6 @@ var _ = Describe("Install Plan", func() { return true, nil }).Should(BeTrue()) }) - - AfterEach(func() { - err := c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), ns.GetName(), metav1.DeleteOptions{}) - Expect(err).ToNot(HaveOccurred()) - - err = crc.OperatorsV1alpha1().InstallPlans(ns.GetName()).Delete(context.TODO(), installPlanName, metav1.DeleteOptions{}) - Expect(err).NotTo(HaveOccurred()) - }) }) When("waiting on the bundle unpacking job", func() { @@ -3329,7 +3496,10 @@ var _ = Describe("Install Plan", func() { AfterEach(func() { Eventually(func() error { - return ctx.Ctx().Client().Delete(context.Background(), ns) + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), ns)) + }, timeout, interval).Should(Succeed(), "could not delete Namespace") + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), ip)) }, timeout, interval).Should(Succeed(), "could not delete Namespace") }) @@ -3471,7 +3641,7 @@ var _ = Describe("Install Plan", func() { c := newKubeClient() crc := newCRClient() - ns, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{ + ns, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.Background(), &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: genName("ns-"), }, @@ -3480,11 +3650,11 @@ var _ = Describe("Install Plan", func() { og := &operatorsv1.OperatorGroup{} og.SetName("og") - _, err = crc.OperatorsV1().OperatorGroups(ns.GetName()).Create(context.TODO(), og, metav1.CreateOptions{}) + _, err = crc.OperatorsV1().OperatorGroups(ns.GetName()).Create(context.Background(), og, metav1.CreateOptions{}) Expect(err).ToNot(HaveOccurred()) deleteOpts := &metav1.DeleteOptions{} - defer c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), ns.GetName(), *deleteOpts) + defer c.KubernetesInterface().CoreV1().Namespaces().Delete(context.Background(), ns.GetName(), *deleteOpts) catsrc := &operatorsv1alpha1.CatalogSource{ ObjectMeta: metav1.ObjectMeta{ @@ -3497,7 +3667,7 @@ var _ = Describe("Install Plan", func() { SourceType: operatorsv1alpha1.SourceTypeGrpc, }, } - catsrc, err = crc.OperatorsV1alpha1().CatalogSources(catsrc.GetNamespace()).Create(context.TODO(), catsrc, metav1.CreateOptions{}) + catsrc, err = crc.OperatorsV1alpha1().CatalogSources(catsrc.GetNamespace()).Create(context.Background(), catsrc, metav1.CreateOptions{}) Expect(err).ToNot(HaveOccurred()) // Wait for the CatalogSource to be ready @@ -3506,7 +3676,8 @@ var _ = Describe("Install Plan", func() { // Generate a Subscription subName := genName("kiali-") - createSubscriptionForCatalog(crc, catsrc.GetNamespace(), subName, catsrc.GetName(), "kiali", stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + cleanUpSubscriptionFn := createSubscriptionForCatalog(crc, catsrc.GetNamespace(), subName, catsrc.GetName(), "kiali", stableChannel, "", operatorsv1alpha1.ApprovalAutomatic) + defer cleanUpSubscriptionFn() sub, err := fetchSubscription(crc, catsrc.GetNamespace(), subName, subscriptionHasInstallPlanChecker) Expect(err).ToNot(HaveOccurred()) @@ -3557,13 +3728,13 @@ var _ = Describe("Install Plan", func() { crc := newCRClient() By("creating a scoped serviceaccount specified in the operatorgroup") - ns, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{ + ns, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.Background(), &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: genName("ns-"), }, }, metav1.CreateOptions{}) Expect(err).ToNot(HaveOccurred()) - defer c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), ns.GetName(), metav1.DeleteOptions{}) + defer c.KubernetesInterface().CoreV1().Namespaces().Delete(context.Background(), ns.GetName(), metav1.DeleteOptions{}) // create SA sa := &corev1.ServiceAccount{ @@ -3572,7 +3743,7 @@ var _ = Describe("Install Plan", func() { Namespace: ns.GetName(), }, } - _, err = c.KubernetesInterface().CoreV1().ServiceAccounts(ns.GetName()).Create(context.TODO(), sa, metav1.CreateOptions{}) + _, err = c.KubernetesInterface().CoreV1().ServiceAccounts(ns.GetName()).Create(context.Background(), sa, metav1.CreateOptions{}) Expect(err).ToNot(HaveOccurred()) // role has no explicit permissions @@ -3603,9 +3774,9 @@ var _ = Describe("Install Plan", func() { }, } - _, err = c.KubernetesInterface().RbacV1().ClusterRoleBindings().Create(context.TODO(), rb, metav1.CreateOptions{}) + _, err = c.KubernetesInterface().RbacV1().ClusterRoleBindings().Create(context.Background(), rb, metav1.CreateOptions{}) Expect(err).ToNot(HaveOccurred()) - defer c.KubernetesInterface().RbacV1().ClusterRoles().Delete(context.TODO(), role.GetName(), metav1.DeleteOptions{}) + defer c.KubernetesInterface().RbacV1().ClusterRoles().Delete(context.Background(), role.GetName(), metav1.DeleteOptions{}) // create operator group referencing the SA og := &operatorsv1.OperatorGroup{ @@ -3617,14 +3788,14 @@ var _ = Describe("Install Plan", func() { ServiceAccountName: sa.GetName(), }, } - _, err = crc.OperatorsV1().OperatorGroups(ns.GetName()).Create(context.TODO(), og, metav1.CreateOptions{}) + _, err = crc.OperatorsV1().OperatorGroups(ns.GetName()).Create(context.Background(), og, metav1.CreateOptions{}) Expect(err).ToNot(HaveOccurred()) // Wait for the OperatorGroup to be synced and have a status.ServiceAccountRef // before moving on. Otherwise the catalog operator treats it as an invalid OperatorGroup // and the InstallPlan is resynced Eventually(func() (*corev1.ObjectReference, error) { - outOG, err := crc.OperatorsV1().OperatorGroups(ns.GetName()).Get(context.TODO(), og.Name, metav1.GetOptions{}) + outOG, err := crc.OperatorsV1().OperatorGroups(ns.GetName()).Get(context.Background(), og.Name, metav1.GetOptions{}) if err != nil { return nil, err } @@ -3665,6 +3836,13 @@ var _ = Describe("Install Plan", func() { }, } + // Defer CRD clean up + defer func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), crd.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + }() + scheme := runtime.NewScheme() Expect(apiextensionsv1.AddToScheme(scheme)).To(Succeed()) var crdManifest bytes.Buffer @@ -3714,7 +3892,7 @@ var _ = Describe("Install Plan", func() { // delete installplan, then create one with an additional resource that the SA does not have permissions to create // expect installplan to fail By("failing to install resources that are not explicitly allowed in the SA") - err = crc.OperatorsV1alpha1().InstallPlans(ns.GetName()).Delete(context.TODO(), plan.GetName(), metav1.DeleteOptions{}) + err = crc.OperatorsV1alpha1().InstallPlans(ns.GetName()).Delete(context.Background(), plan.GetName(), metav1.DeleteOptions{}) Expect(err).ToNot(HaveOccurred()) service := &corev1.Service{ @@ -3723,7 +3901,7 @@ var _ = Describe("Install Plan", func() { APIVersion: "v1", }, ObjectMeta: metav1.ObjectMeta{ - Namespace: testNamespace, + Namespace: ns.GetName(), Name: "test-service", }, Spec: corev1.ServiceSpec{ @@ -3781,6 +3959,11 @@ var _ = Describe("Install Plan", func() { Eventually(func() (*operatorsv1alpha1.InstallPlan, error) { return newPlan, ctx.Ctx().Client().Get(context.Background(), newKey, newPlan) }).Should(HavePhase(operatorsv1alpha1.InstallPlanPhaseFailed)) + + Expect(client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), &crd))).To(Succeed()) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), ns)) + }, timeout, interval).Should(Succeed(), "could not delete Namespace") }) It("uses the correct client when installing resources from an installplan", func() { @@ -3788,13 +3971,13 @@ var _ = Describe("Install Plan", func() { crc := newCRClient() By("creating a scoped serviceaccount specifified in the operatorgroup") - ns, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), &corev1.Namespace{ + ns, err := c.KubernetesInterface().CoreV1().Namespaces().Create(context.Background(), &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: genName("ns-"), }, }, metav1.CreateOptions{}) Expect(err).ToNot(HaveOccurred()) - defer c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), ns.GetName(), metav1.DeleteOptions{}) + defer c.KubernetesInterface().CoreV1().Namespaces().Delete(context.Background(), ns.GetName(), metav1.DeleteOptions{}) // create SA sa := &corev1.ServiceAccount{ @@ -3803,7 +3986,7 @@ var _ = Describe("Install Plan", func() { Namespace: ns.GetName(), }, } - _, err = c.KubernetesInterface().CoreV1().ServiceAccounts(ns.GetName()).Create(context.TODO(), sa, metav1.CreateOptions{}) + _, err = c.KubernetesInterface().CoreV1().ServiceAccounts(ns.GetName()).Create(context.Background(), sa, metav1.CreateOptions{}) Expect(err).ToNot(HaveOccurred()) // see https://github.com/operator-framework/operator-lifecycle-manager/blob/master/doc/design/scoped-operator-install.md @@ -3836,7 +4019,7 @@ var _ = Describe("Install Plan", func() { }, } - _, err = c.KubernetesInterface().RbacV1().ClusterRoles().Create(context.TODO(), role, metav1.CreateOptions{}) + _, err = c.KubernetesInterface().RbacV1().ClusterRoles().Create(context.Background(), role, metav1.CreateOptions{}) Expect(err).ToNot(HaveOccurred()) // bind role to SA @@ -3859,9 +4042,9 @@ var _ = Describe("Install Plan", func() { }, } - _, err = c.KubernetesInterface().RbacV1().ClusterRoleBindings().Create(context.TODO(), rb, metav1.CreateOptions{}) + _, err = c.KubernetesInterface().RbacV1().ClusterRoleBindings().Create(context.Background(), rb, metav1.CreateOptions{}) Expect(err).ToNot(HaveOccurred()) - defer c.KubernetesInterface().RbacV1().ClusterRoles().Delete(context.TODO(), role.GetName(), metav1.DeleteOptions{}) + defer c.KubernetesInterface().RbacV1().ClusterRoles().Delete(context.Background(), role.GetName(), metav1.DeleteOptions{}) // create operator group referencing the SA og := &operatorsv1.OperatorGroup{ @@ -3873,14 +4056,14 @@ var _ = Describe("Install Plan", func() { ServiceAccountName: sa.GetName(), }, } - _, err = crc.OperatorsV1().OperatorGroups(ns.GetName()).Create(context.TODO(), og, metav1.CreateOptions{}) + _, err = crc.OperatorsV1().OperatorGroups(ns.GetName()).Create(context.Background(), og, metav1.CreateOptions{}) Expect(err).ToNot(HaveOccurred()) // Wait for the OperatorGroup to be synced and have a status.ServiceAccountRef // before moving on. Otherwise the catalog operator treats it as an invalid OperatorGroup // and the InstallPlan is resynced Eventually(func() (*corev1.ObjectReference, error) { - outOG, err := crc.OperatorsV1().OperatorGroups(ns.GetName()).Get(context.TODO(), og.Name, metav1.GetOptions{}) + outOG, err := crc.OperatorsV1().OperatorGroups(ns.GetName()).Get(context.Background(), og.Name, metav1.GetOptions{}) if err != nil { return nil, err } @@ -3924,6 +4107,16 @@ var _ = Describe("Install Plan", func() { } csv := newCSV("stable", ns.GetName(), "", semver.MustParse("0.1.0"), nil, nil, nil) + // Defer CRD clean up + defer func() { + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().KubeClient().ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Delete(context.Background(), crd.GetName(), metav1.DeleteOptions{})) + }).Should(Succeed()) + Eventually(func() error { + return client.IgnoreNotFound(ctx.Ctx().Client().Delete(context.Background(), &csv)) + }).Should(Succeed()) + }() + scheme := runtime.NewScheme() Expect(apiextensionsv1.AddToScheme(scheme)).To(Succeed()) Expect(operatorsv1alpha1.AddToScheme(scheme)).To(Succeed()) @@ -3983,7 +4176,7 @@ var _ = Describe("Install Plan", func() { // delete installplan, and create one with just a CSV resource which should succeed By("installing additional resources that are allowed in the SA") - err = crc.OperatorsV1alpha1().InstallPlans(ns.GetName()).Delete(context.TODO(), plan.GetName(), metav1.DeleteOptions{}) + err = crc.OperatorsV1alpha1().InstallPlans(ns.GetName()).Delete(context.Background(), plan.GetName(), metav1.DeleteOptions{}) Expect(err).ToNot(HaveOccurred()) newPlan := &operatorsv1alpha1.InstallPlan{ @@ -4026,7 +4219,6 @@ var _ = Describe("Install Plan", func() { Eventually(func() (*operatorsv1alpha1.InstallPlan, error) { return newPlan, ctx.Ctx().Client().Get(context.Background(), newKey, newPlan) }).Should(HavePhase(operatorsv1alpha1.InstallPlanPhaseComplete)) - }) }) @@ -4034,7 +4226,7 @@ type checkInstallPlanFunc func(fip *operatorsv1alpha1.InstallPlan) bool func validateCRDVersions(t GinkgoTInterface, c operatorclient.ClientInterface, name string, expectedVersions map[string]struct{}) { // Retrieve CRD information - crd, err := c.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), name, metav1.GetOptions{}) + crd, err := c.ApiextensionsInterface().ApiextensionsV1().CustomResourceDefinitions().Get(context.Background(), name, metav1.GetOptions{}) require.NoError(t, err) require.Equal(t, len(expectedVersions), len(crd.Spec.Versions), "number of CRD versions don't not match installed") @@ -4067,18 +4259,18 @@ func buildInstallPlanCleanupFunc(crc versioned.Interface, namespace string, inst deleteOptions := &metav1.DeleteOptions{} for _, step := range installPlan.Status.Plan { if step.Resource.Kind == operatorsv1alpha1.ClusterServiceVersionKind { - if err := crc.OperatorsV1alpha1().ClusterServiceVersions(namespace).Delete(context.TODO(), step.Resource.Name, *deleteOptions); err != nil { + if err := crc.OperatorsV1alpha1().ClusterServiceVersions(namespace).Delete(context.Background(), step.Resource.Name, *deleteOptions); err != nil { fmt.Println(err) } } } - if err := crc.OperatorsV1alpha1().InstallPlans(namespace).Delete(context.TODO(), installPlan.GetName(), *deleteOptions); err != nil { + if err := crc.OperatorsV1alpha1().InstallPlans(namespace).Delete(context.Background(), installPlan.GetName(), *deleteOptions); err != nil { fmt.Println(err) } err := waitForDelete(func() error { - _, err := crc.OperatorsV1alpha1().InstallPlans(namespace).Get(context.TODO(), installPlan.GetName(), metav1.GetOptions{}) + _, err := crc.OperatorsV1alpha1().InstallPlans(namespace).Get(context.Background(), installPlan.GetName(), metav1.GetOptions{}) return err }) @@ -4097,7 +4289,7 @@ func fetchInstallPlanWithNamespace(t GinkgoTInterface, c versioned.Interface, na var err error err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { - fetchedInstallPlan, err = c.OperatorsV1alpha1().InstallPlans(namespace).Get(context.TODO(), name, metav1.GetOptions{}) + fetchedInstallPlan, err = c.OperatorsV1alpha1().InstallPlans(namespace).Get(context.Background(), name, metav1.GetOptions{}) if err != nil || fetchedInstallPlan == nil { return false, err } @@ -4113,8 +4305,8 @@ func waitForInstallPlan(c versioned.Interface, name string, namespace string, ch var err error err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { - fetchedInstallPlan, err = c.OperatorsV1alpha1().InstallPlans(namespace).Get(context.TODO(), name, metav1.GetOptions{}) - if err != nil && !k8serrors.IsNotFound(err) { + fetchedInstallPlan, err = c.OperatorsV1alpha1().InstallPlans(namespace).Get(context.Background(), name, metav1.GetOptions{}) + if err != nil && !apierrors.IsNotFound(err) { return false, err } diff --git a/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go index f89bc2b7e1..a625637f17 100644 --- a/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/metrics_e2e_test.go @@ -33,14 +33,20 @@ import ( var _ = Describe("Metrics are generated for OLM managed resources", func() { var ( - c operatorclient.ClientInterface - crc versioned.Interface + c operatorclient.ClientInterface + crc versioned.Interface + generatedNamespace corev1.Namespace ) BeforeEach(func() { c = newKubeClient() crc = newCRClient() + namespaceName := genName("metrics-e2e-") + generatedNamespace = SetupGeneratedTestNamespace(namespaceName, namespaceName) + }) + AfterEach(func() { + TeardownNamespace(generatedNamespace.GetName()) }) Context("Given an OperatorGroup that supports all namespaces", func() { @@ -74,10 +80,10 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { } var err error - cleanupCSV, err = createCSV(c, crc, failingCSV, testNamespace, false, false) + cleanupCSV, err = createCSV(c, crc, failingCSV, generatedNamespace.GetName(), false, false) Expect(err).ToNot(HaveOccurred()) - _, err = fetchCSV(crc, failingCSV.Name, testNamespace, csvFailedChecker) + _, err = fetchCSV(crc, failingCSV.Name, generatedNamespace.GetName(), csvFailedChecker) Expect(err).ToNot(HaveOccurred()) }) @@ -127,12 +133,12 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { BeforeEach(func() { packageName := genName("csv-test-") packageStable := fmt.Sprintf("%s-stable", packageName) - csv = newCSV(packageStable, testNamespace, "", semver.MustParse("0.1.0"), nil, nil, nil) + csv = newCSV(packageStable, generatedNamespace.GetName(), "", semver.MustParse("0.1.0"), nil, nil, nil) var err error - _, err = createCSV(c, crc, csv, testNamespace, false, false) + _, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).ToNot(HaveOccurred()) - _, err = fetchCSV(crc, csv.Name, testNamespace, csvSucceededChecker) + _, err = fetchCSV(crc, csv.Name, generatedNamespace.GetName(), csvSucceededChecker) Expect(err).ToNot(HaveOccurred()) }) AfterEach(func() { @@ -170,7 +176,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { When("A subscription object is created", func() { BeforeEach(func() { - subscriptionCleanup, _ = createSubscription(GinkgoT(), crc, testNamespace, "metric-subscription-for-create", testPackageName, stableChannel, v1alpha1.ApprovalManual) + subscriptionCleanup, _ = createSubscription(GinkgoT(), crc, generatedNamespace.GetName(), "metric-subscription-for-create", testPackageName, stableChannel, v1alpha1.ApprovalManual) }) AfterEach(func() { @@ -211,17 +217,17 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { When("A subscription object is updated after emitting metrics", func() { BeforeEach(func() { - subscriptionCleanup, subscription = createSubscription(GinkgoT(), crc, testNamespace, "metric-subscription-for-update", testPackageName, stableChannel, v1alpha1.ApprovalManual) + subscriptionCleanup, subscription = createSubscription(GinkgoT(), crc, generatedNamespace.GetName(), "metric-subscription-for-update", testPackageName, stableChannel, v1alpha1.ApprovalManual) Eventually(func() []Metric { return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator")) }).Should(ContainElement(LikeMetric(WithFamily("subscription_sync_total"), WithLabel("name", "metric-subscription-for-update")))) Eventually(func() error { - s, err := crc.OperatorsV1alpha1().Subscriptions(subscription.GetNamespace()).Get(context.TODO(), subscription.GetName(), metav1.GetOptions{}) + s, err := crc.OperatorsV1alpha1().Subscriptions(subscription.GetNamespace()).Get(context.Background(), subscription.GetName(), metav1.GetOptions{}) if err != nil { return err } s.Spec.Channel = betaChannel - _, err = crc.OperatorsV1alpha1().Subscriptions(s.GetNamespace()).Update(context.TODO(), s, metav1.UpdateOptions{}) + _, err = crc.OperatorsV1alpha1().Subscriptions(s.GetNamespace()).Update(context.Background(), s, metav1.UpdateOptions{}) return err }).Should(Succeed()) }) @@ -256,12 +262,12 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { BeforeEach(func() { Eventually(func() error { - s, err := crc.OperatorsV1alpha1().Subscriptions(subscription.GetNamespace()).Get(context.TODO(), subscription.GetName(), metav1.GetOptions{}) + s, err := crc.OperatorsV1alpha1().Subscriptions(subscription.GetNamespace()).Get(context.Background(), subscription.GetName(), metav1.GetOptions{}) if err != nil { return err } s.Spec.Channel = alphaChannel - _, err = crc.OperatorsV1alpha1().Subscriptions(s.GetNamespace()).Update(context.TODO(), s, metav1.UpdateOptions{}) + _, err = crc.OperatorsV1alpha1().Subscriptions(s.GetNamespace()).Update(context.Background(), s, metav1.UpdateOptions{}) return err }).Should(Succeed()) }) @@ -296,7 +302,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { When("A subscription object is deleted after emitting metrics", func() { BeforeEach(func() { - subscriptionCleanup, subscription = createSubscription(GinkgoT(), crc, testNamespace, "metric-subscription-for-delete", testPackageName, stableChannel, v1alpha1.ApprovalManual) + subscriptionCleanup, subscription = createSubscription(GinkgoT(), crc, generatedNamespace.GetName(), "metric-subscription-for-delete", testPackageName, stableChannel, v1alpha1.ApprovalManual) Eventually(func() []Metric { return getMetricsFromPod(c, getPodWithLabel(c, "app=catalog-operator")) }).Should(ContainElement(LikeMetric(WithFamily("subscription_sync_total"), WithLabel("name", "metric-subscription-for-delete")))) @@ -334,7 +340,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { stableChannel := "stable" mainCRD := newCRD(genName("ins-")) - mainCSV := newCSV(mainPackageStable, testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, nil) + mainCSV := newCSV(mainPackageStable, generatedNamespace.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{mainCRD}, nil, nil) mainManifests := []registry.PackageManifest{ { @@ -345,7 +351,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { DefaultChannelName: stableChannel, }, } - cs, cleanupAll := createInternalCatalogSource(c, crc, name, testNamespace, mainManifests, []apiextensions.CustomResourceDefinition{mainCRD}, []v1alpha1.ClusterServiceVersion{mainCSV}) + cs, cleanupAll := createInternalCatalogSource(c, crc, name, generatedNamespace.GetName(), mainManifests, []apiextensions.CustomResourceDefinition{mainCRD}, []v1alpha1.ClusterServiceVersion{mainCSV}) // Note(tflannag): Dependending on how ginkgo orders these test specs, and how bloated the cluster we're running // this test case against, we risk creating and then immediately deleting the catalogsource before the catalog // operator can generate all the requisite resources (e.g. the ServiceAccount), which can leave the underlying @@ -373,7 +379,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { ContainElement(LikeMetric( WithFamily("catalogsource_ready"), WithName(name), - WithNamespace(testNamespace), + WithNamespace(generatedNamespace.GetName()), WithValue(1), )), )) @@ -389,7 +395,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { Not(ContainElement(LikeMetric( WithFamily("catalogsource_ready"), WithName(name), - WithNamespace(testNamespace), + WithNamespace(generatedNamespace.GetName()), ))))) }) }) @@ -401,7 +407,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { cleanup func() ) BeforeEach(func() { - _, cleanup = createInvalidGRPCCatalogSource(crc, name, testNamespace) + _, cleanup = createInvalidGRPCCatalogSource(crc, name, generatedNamespace.GetName()) }) AfterEach(func() { cleanup() @@ -413,7 +419,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { ContainElement(LikeMetric( WithFamily("catalogsource_ready"), WithName(name), - WithNamespace(testNamespace), + WithNamespace(generatedNamespace.GetName()), WithValue(0), )), )) @@ -423,7 +429,7 @@ var _ = Describe("Metrics are generated for OLM managed resources", func() { ContainElement(LikeMetric( WithFamily("catalogsource_ready"), WithName(name), - WithNamespace(testNamespace), + WithNamespace(generatedNamespace.GetName()), WithValue(0), )), )) @@ -436,7 +442,7 @@ func getPodWithLabel(client operatorclient.ClientInterface, label string) *corev listOptions := metav1.ListOptions{LabelSelector: label} var podList *corev1.PodList EventuallyWithOffset(1, func() (numPods int, err error) { - podList, err = client.KubernetesInterface().CoreV1().Pods(operatorNamespace).List(context.TODO(), listOptions) + podList, err = client.KubernetesInterface().CoreV1().Pods(operatorNamespace).List(context.Background(), listOptions) if podList != nil { numPods = len(podList.Items) } @@ -451,7 +457,7 @@ func getDeploymentWithLabel(client operatorclient.ClientInterface, label string) listOptions := metav1.ListOptions{LabelSelector: label} var deploymentList *appsv1.DeploymentList EventuallyWithOffset(1, func() (numDeps int, err error) { - deploymentList, err = client.KubernetesInterface().AppsV1().Deployments(operatorNamespace).List(context.TODO(), listOptions) + deploymentList, err = client.KubernetesInterface().AppsV1().Deployments(operatorNamespace).List(context.Background(), listOptions) if deploymentList != nil { numDeps = len(deploymentList.Items) } @@ -467,11 +473,11 @@ func restartDeploymentWithLabel(client operatorclient.ClientInterface, l string) z := int32(0) oldZ := *d.Spec.Replicas d.Spec.Replicas = &z - _, err := client.KubernetesInterface().AppsV1().Deployments(operatorNamespace).Update(context.TODO(), d, metav1.UpdateOptions{}) + _, err := client.KubernetesInterface().AppsV1().Deployments(operatorNamespace).Update(context.Background(), d, metav1.UpdateOptions{}) Expect(err).ToNot(HaveOccurred()) EventuallyWithOffset(1, func() (replicas int32, err error) { - deployment, err := client.KubernetesInterface().AppsV1().Deployments(operatorNamespace).Get(context.TODO(), d.Name, metav1.GetOptions{}) + deployment, err := client.KubernetesInterface().AppsV1().Deployments(operatorNamespace).Get(context.Background(), d.Name, metav1.GetOptions{}) if deployment != nil { replicas = deployment.Status.Replicas } @@ -480,11 +486,11 @@ func restartDeploymentWithLabel(client operatorclient.ClientInterface, l string) updated := getDeploymentWithLabel(client, l) updated.Spec.Replicas = &oldZ - _, err = client.KubernetesInterface().AppsV1().Deployments(operatorNamespace).Update(context.TODO(), updated, metav1.UpdateOptions{}) + _, err = client.KubernetesInterface().AppsV1().Deployments(operatorNamespace).Update(context.Background(), updated, metav1.UpdateOptions{}) Expect(err).ToNot(HaveOccurred()) EventuallyWithOffset(1, func() (replicas int32, err error) { - deployment, err := client.KubernetesInterface().AppsV1().Deployments(operatorNamespace).Get(context.TODO(), d.Name, metav1.GetOptions{}) + deployment, err := client.KubernetesInterface().AppsV1().Deployments(operatorNamespace).Get(context.Background(), d.Name, metav1.GetOptions{}) if deployment != nil { replicas = deployment.Status.Replicas } diff --git a/staging/operator-lifecycle-manager/test/e2e/operator_condition_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/operator_condition_e2e_test.go index ae2b69cae3..b98240f240 100644 --- a/staging/operator-lifecycle-manager/test/e2e/operator_condition_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/operator_condition_e2e_test.go @@ -7,6 +7,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" meta "k8s.io/apimachinery/pkg/api/meta" @@ -18,8 +19,17 @@ import ( ) var _ = Describe("Operator Condition", func() { + + var ( + generatedNamespace corev1.Namespace + ) + + BeforeEach(func() { + generatedNamespace = SetupGeneratedTestNamespace(genName("operator-conditions-e2e-")) + }) + AfterEach(func() { - TearDown(testNamespace) + TeardownNamespace(generatedNamespace.GetName()) }) It("OperatorCondition Upgradeable type and overrides", func() { @@ -44,9 +54,9 @@ var _ = Describe("Operator Condition", func() { strategyB := newNginxInstallStrategy(pkgBStable, nil, nil) strategyD := newNginxInstallStrategy(pkgDStable, nil, nil) crd := newCRD(genName(pkgA)) - csvA := newCSV(pkgAStable, testNamespace, "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd}, nil, &strategyA) - csvB := newCSV(pkgBStable, testNamespace, pkgAStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{crd}, nil, &strategyB) - csvD := newCSV(pkgDStable, testNamespace, pkgBStable, semver.MustParse("0.3.0"), []apiextensions.CustomResourceDefinition{crd}, nil, &strategyD) + csvA := newCSV(pkgAStable, generatedNamespace.GetName(), "", semver.MustParse("0.1.0"), []apiextensions.CustomResourceDefinition{crd}, nil, &strategyA) + csvB := newCSV(pkgBStable, generatedNamespace.GetName(), pkgAStable, semver.MustParse("0.2.0"), []apiextensions.CustomResourceDefinition{crd}, nil, &strategyB) + csvD := newCSV(pkgDStable, generatedNamespace.GetName(), pkgBStable, semver.MustParse("0.3.0"), []apiextensions.CustomResourceDefinition{crd}, nil, &strategyD) // Create the initial catalogsources manifests := []registry.PackageManifest{ @@ -60,15 +70,15 @@ var _ = Describe("Operator Condition", func() { } catalog := genName("catalog-") - _, cleanupCatalogSource := createInternalCatalogSource(c, crc, catalog, testNamespace, manifests, []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{csvA}) + _, cleanupCatalogSource := createInternalCatalogSource(c, crc, catalog, generatedNamespace.GetName(), manifests, []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{csvA}) defer cleanupCatalogSource() - _, err := fetchCatalogSourceOnStatus(crc, catalog, testNamespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crc, catalog, generatedNamespace.GetName(), catalogSourceRegistryPodSynced) subName := genName("sub-") - cleanupSub := createSubscriptionForCatalog(crc, testNamespace, subName, catalog, pkgA, stableChannel, pkgAStable, operatorsv1alpha1.ApprovalAutomatic) + cleanupSub := createSubscriptionForCatalog(crc, generatedNamespace.GetName(), subName, catalog, pkgA, stableChannel, pkgAStable, operatorsv1alpha1.ApprovalAutomatic) defer cleanupSub() // Await csvA's success - _, err = awaitCSV(crc, testNamespace, csvA.GetName(), csvSucceededChecker) + _, err = awaitCSV(crc, generatedNamespace.GetName(), csvA.GetName(), csvSucceededChecker) require.NoError(GinkgoT(), err) // Get the OperatorCondition for csvA and report that it is not upgradeable @@ -83,14 +93,14 @@ var _ = Describe("Operator Condition", func() { var currentGen int64 Eventually(func() error { - cond, err := crc.OperatorsV2().OperatorConditions(testNamespace).Get(context.TODO(), csvA.GetName(), metav1.GetOptions{}) + cond, err := crc.OperatorsV2().OperatorConditions(generatedNamespace.GetName()).Get(context.TODO(), csvA.GetName(), metav1.GetOptions{}) if err != nil { return err } currentGen = cond.ObjectMeta.GetGeneration() upgradeableFalseCondition.ObservedGeneration = currentGen meta.SetStatusCondition(&cond.Spec.Conditions, upgradeableFalseCondition) - _, err = crc.OperatorsV2().OperatorConditions(testNamespace).Update(context.TODO(), cond, metav1.UpdateOptions{}) + _, err = crc.OperatorsV2().OperatorConditions(generatedNamespace.GetName()).Update(context.TODO(), cond, metav1.UpdateOptions{}) return err }, pollInterval, pollDuration).Should(Succeed()) @@ -104,14 +114,14 @@ var _ = Describe("Operator Condition", func() { DefaultChannelName: stableChannel, }, } - updateInternalCatalog(GinkgoT(), c, crc, catalog, testNamespace, []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{csvA, csvB}, manifests) + updateInternalCatalog(GinkgoT(), c, crc, catalog, generatedNamespace.GetName(), []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{csvA, csvB}, manifests) // Attempt to get the catalog source before creating install plan(s) - _, err = fetchCatalogSourceOnStatus(crc, catalog, testNamespace, catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, catalog, generatedNamespace.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) // csvB will be in Pending phase due to csvA reports Upgradeable=False condition - fetchedCSV, err := fetchCSV(crc, csvB.GetName(), testNamespace, buildCSVReasonChecker(operatorsv1alpha1.CSVReasonOperatorConditionNotUpgradeable)) + fetchedCSV, err := fetchCSV(crc, csvB.GetName(), generatedNamespace.GetName(), buildCSVReasonChecker(operatorsv1alpha1.CSVReasonOperatorConditionNotUpgradeable)) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), fetchedCSV.Status.Phase, operatorsv1alpha1.CSVPhasePending) @@ -124,32 +134,32 @@ var _ = Describe("Operator Condition", func() { LastTransitionTime: metav1.Now(), } Eventually(func() error { - cond, err = crc.OperatorsV2().OperatorConditions(testNamespace).Get(context.TODO(), csvA.GetName(), metav1.GetOptions{}) + cond, err = crc.OperatorsV2().OperatorConditions(generatedNamespace.GetName()).Get(context.TODO(), csvA.GetName(), metav1.GetOptions{}) if err != nil || currentGen == cond.ObjectMeta.GetGeneration() { return err } currentGen = cond.ObjectMeta.GetGeneration() upgradeableTrueCondition.ObservedGeneration = cond.ObjectMeta.GetGeneration() meta.SetStatusCondition(&cond.Spec.Conditions, upgradeableTrueCondition) - _, err = crc.OperatorsV2().OperatorConditions(testNamespace).Update(context.TODO(), cond, metav1.UpdateOptions{}) + _, err = crc.OperatorsV2().OperatorConditions(generatedNamespace.GetName()).Update(context.TODO(), cond, metav1.UpdateOptions{}) return err }, pollInterval, pollDuration).Should(Succeed()) // Await csvB's success - _, err = awaitCSV(crc, testNamespace, csvB.GetName(), csvSucceededChecker) + _, err = awaitCSV(crc, generatedNamespace.GetName(), csvB.GetName(), csvSucceededChecker) require.NoError(GinkgoT(), err) // Get the OperatorCondition for csvB and purposedly change ObservedGeneration // to cause mismatch generation situation Eventually(func() error { - cond, err = crc.OperatorsV2().OperatorConditions(testNamespace).Get(context.TODO(), csvB.GetName(), metav1.GetOptions{}) + cond, err = crc.OperatorsV2().OperatorConditions(generatedNamespace.GetName()).Get(context.TODO(), csvB.GetName(), metav1.GetOptions{}) if err != nil || currentGen == cond.ObjectMeta.GetGeneration() { return err } currentGen = cond.ObjectMeta.GetGeneration() upgradeableTrueCondition.ObservedGeneration = currentGen + 1 meta.SetStatusCondition(&cond.Status.Conditions, upgradeableTrueCondition) - _, err = crc.OperatorsV2().OperatorConditions(testNamespace).UpdateStatus(context.TODO(), cond, metav1.UpdateOptions{}) + _, err = crc.OperatorsV2().OperatorConditions(generatedNamespace.GetName()).UpdateStatus(context.TODO(), cond, metav1.UpdateOptions{}) return err }, pollInterval, pollDuration).Should(Succeed()) @@ -164,31 +174,31 @@ var _ = Describe("Operator Condition", func() { }, } - updateInternalCatalog(GinkgoT(), c, crc, catalog, testNamespace, []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{csvA, csvB, csvD}, manifests) + updateInternalCatalog(GinkgoT(), c, crc, catalog, generatedNamespace.GetName(), []apiextensions.CustomResourceDefinition{crd}, []operatorsv1alpha1.ClusterServiceVersion{csvA, csvB, csvD}, manifests) // Attempt to get the catalog source before creating install plan(s) - _, err = fetchCatalogSourceOnStatus(crc, catalog, testNamespace, catalogSourceRegistryPodSynced) + _, err = fetchCatalogSourceOnStatus(crc, catalog, generatedNamespace.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) // CSVD will be in Pending status due to overrides in csvB's condition - fetchedCSV, err = fetchCSV(crc, csvD.GetName(), testNamespace, buildCSVReasonChecker(operatorsv1alpha1.CSVReasonOperatorConditionNotUpgradeable)) + fetchedCSV, err = fetchCSV(crc, csvD.GetName(), generatedNamespace.GetName(), buildCSVReasonChecker(operatorsv1alpha1.CSVReasonOperatorConditionNotUpgradeable)) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), fetchedCSV.Status.Phase, operatorsv1alpha1.CSVPhasePending) // Get the OperatorCondition for csvB and override the upgradeable false condition Eventually(func() error { - cond, err = crc.OperatorsV2().OperatorConditions(testNamespace).Get(context.TODO(), csvB.GetName(), metav1.GetOptions{}) + cond, err = crc.OperatorsV2().OperatorConditions(generatedNamespace.GetName()).Get(context.TODO(), csvB.GetName(), metav1.GetOptions{}) if err != nil { return err } meta.SetStatusCondition(&cond.Spec.Overrides, upgradeableTrueCondition) // Update the condition - _, err = crc.OperatorsV2().OperatorConditions(testNamespace).Update(context.TODO(), cond, metav1.UpdateOptions{}) + _, err = crc.OperatorsV2().OperatorConditions(generatedNamespace.GetName()).Update(context.TODO(), cond, metav1.UpdateOptions{}) return err }, pollInterval, pollDuration).Should(Succeed()) require.NoError(GinkgoT(), err) require.NoError(GinkgoT(), err) - _, err = awaitCSV(crc, testNamespace, csvD.GetName(), csvSucceededChecker) + _, err = awaitCSV(crc, generatedNamespace.GetName(), csvD.GetName(), csvSucceededChecker) require.NoError(GinkgoT(), err) }) }) diff --git a/staging/operator-lifecycle-manager/test/e2e/operator_groups_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/operator_groups_e2e_test.go index 8954dacf0c..18a1e5d456 100644 --- a/staging/operator-lifecycle-manager/test/e2e/operator_groups_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/operator_groups_e2e_test.go @@ -14,7 +14,7 @@ import ( corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/wait" @@ -218,7 +218,7 @@ var _ = Describe("Operator Group", func() { err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(opGroupNamespace).Get(context.TODO(), csvName, metav1.GetOptions{}) if fetchErr != nil { - if k8serrors.IsNotFound(fetchErr) { + if apierrors.IsNotFound(fetchErr) { return false, nil } log(fmt.Sprintf("Error (in %v): %v", testNamespace, fetchErr.Error())) @@ -235,7 +235,7 @@ var _ = Describe("Operator Group", func() { err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(context.TODO(), csvName, metav1.GetOptions{}) if fetchErr != nil { - if k8serrors.IsNotFound(fetchErr) { + if apierrors.IsNotFound(fetchErr) { return false, nil } log(fmt.Sprintf("Error (in %v): %v", otherNamespaceName, fetchErr.Error())) @@ -252,7 +252,7 @@ var _ = Describe("Operator Group", func() { err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(context.TODO(), csvName, metav1.GetOptions{}) if fetchErr != nil { - if k8serrors.IsNotFound(fetchErr) { + if apierrors.IsNotFound(fetchErr) { return false, nil } GinkgoT().Logf("Error (in %v): %v", otherNamespaceName, fetchErr.Error()) @@ -269,7 +269,7 @@ var _ = Describe("Operator Group", func() { err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { createdDeployment, err := c.GetDeployment(opGroupNamespace, deploymentName) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return false, nil } return false, err @@ -387,7 +387,7 @@ var _ = Describe("Operator Group", func() { } return true, err }) - require.True(GinkgoT(), k8serrors.IsNotFound(err)) + require.True(GinkgoT(), apierrors.IsNotFound(err)) err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { _, err := c.KubernetesInterface().RbacV1().ClusterRoles().Get(context.TODO(), operatorGroup.Name+"-edit", metav1.GetOptions{}) @@ -396,7 +396,7 @@ var _ = Describe("Operator Group", func() { } return true, err }) - require.True(GinkgoT(), k8serrors.IsNotFound(err)) + require.True(GinkgoT(), apierrors.IsNotFound(err)) err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { _, err := c.KubernetesInterface().RbacV1().ClusterRoles().Get(context.TODO(), operatorGroup.Name+"-view", metav1.GetOptions{}) @@ -405,7 +405,7 @@ var _ = Describe("Operator Group", func() { } return true, err }) - require.True(GinkgoT(), k8serrors.IsNotFound(err)) + require.True(GinkgoT(), apierrors.IsNotFound(err)) }) It("role aggregation", func() { @@ -1084,7 +1084,7 @@ var _ = Describe("Operator Group", func() { require.NoError(GinkgoT(), awaitAnnotations(GinkgoT(), q, map[string]string{v1.OperatorGroupProvidedAPIsAnnotationKey: ""})) // Ensure csvA's deployment is deleted - require.NoError(GinkgoT(), waitForDeploymentToDelete(c, pkgAStable)) + require.NoError(GinkgoT(), waitForDeploymentToDelete(testNamespace, c, pkgAStable)) // Await csvB's success _, err = awaitCSV(crc, nsB, csvB.GetName(), csvSucceededChecker) @@ -1440,7 +1440,7 @@ var _ = Describe("Operator Group", func() { err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { fetchedRole, err = c.GetClusterRole(role.GetName()) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return false, nil } return false, err @@ -1456,7 +1456,7 @@ var _ = Describe("Operator Group", func() { err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { fetchedRoleBinding, err = c.GetClusterRoleBinding(roleBinding.GetName()) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return false, nil } return false, err @@ -1485,7 +1485,7 @@ var _ = Describe("Operator Group", func() { err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(opGroupNamespace).Get(context.TODO(), csvName, metav1.GetOptions{}) if fetchErr != nil { - if k8serrors.IsNotFound(fetchErr) { + if apierrors.IsNotFound(fetchErr) { return false, nil } GinkgoT().Logf("Error (in %v): %v", testNamespace, fetchErr.Error()) @@ -1518,7 +1518,7 @@ var _ = Describe("Operator Group", func() { err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(context.TODO(), csvName, metav1.GetOptions{}) if fetchErr != nil { - if k8serrors.IsNotFound(fetchErr) { + if apierrors.IsNotFound(fetchErr) { return false, nil } GinkgoT().Logf("Error (in %v): %v", otherNamespaceName, fetchErr.Error()) @@ -1549,7 +1549,7 @@ var _ = Describe("Operator Group", func() { err = wait.Poll(pollInterval, 2*pollDuration, func() (bool, error) { _, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(context.TODO(), csvName, metav1.GetOptions{}) if fetchErr != nil { - if k8serrors.IsNotFound(fetchErr) { + if apierrors.IsNotFound(fetchErr) { return true, nil } GinkgoT().Logf("Error (in %v): %v", opGroupNamespace, fetchErr.Error()) @@ -1921,7 +1921,7 @@ var _ = Describe("Operator Group", func() { err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { fetchedRole, err = c.GetClusterRole(role.GetName()) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return false, nil } return false, err @@ -1937,7 +1937,7 @@ var _ = Describe("Operator Group", func() { err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { fetchedRoleBinding, err = c.GetClusterRoleBinding(roleBinding.GetName()) if err != nil { - if k8serrors.IsNotFound(err) { + if apierrors.IsNotFound(err) { return false, nil } return false, err @@ -1966,7 +1966,7 @@ var _ = Describe("Operator Group", func() { err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(opGroupNamespace).Get(context.TODO(), csvName, metav1.GetOptions{}) if fetchErr != nil { - if k8serrors.IsNotFound(fetchErr) { + if apierrors.IsNotFound(fetchErr) { return false, nil } GinkgoT().Logf("Error (in %v): %v", testNamespace, fetchErr.Error()) @@ -1999,7 +1999,7 @@ var _ = Describe("Operator Group", func() { err = wait.Poll(pollInterval, pollDuration, func() (bool, error) { fetchedCSV, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(context.TODO(), csvName, metav1.GetOptions{}) if fetchErr != nil { - if k8serrors.IsNotFound(fetchErr) { + if apierrors.IsNotFound(fetchErr) { return false, nil } GinkgoT().Logf("Error (in %v): %v", otherNamespaceName, fetchErr.Error()) @@ -2026,7 +2026,7 @@ var _ = Describe("Operator Group", func() { err = wait.Poll(pollInterval, 2*pollDuration, func() (bool, error) { csv, fetchErr := crc.OperatorsV1alpha1().ClusterServiceVersions(otherNamespaceName).Get(context.TODO(), csvName, metav1.GetOptions{}) if fetchErr != nil { - if k8serrors.IsNotFound(fetchErr) { + if apierrors.IsNotFound(fetchErr) { return true, nil } GinkgoT().Logf("Error (in %v): %v", opGroupNamespace, fetchErr.Error()) diff --git a/staging/operator-lifecycle-manager/test/e2e/scoped_client_test.go b/staging/operator-lifecycle-manager/test/e2e/scoped_client_test.go index 028b941039..bed19da6be 100644 --- a/staging/operator-lifecycle-manager/test/e2e/scoped_client_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/scoped_client_test.go @@ -8,7 +8,7 @@ import ( . "github.com/onsi/gomega" "github.com/sirupsen/logrus" corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/rest" @@ -55,7 +55,7 @@ var _ = Describe("Scoped Client bound to a service account can be used to make A // We expect the get api call to return 'Forbidden' error due to // lack of permission. assertFunc: func(errGot error) { - Expect(k8serrors.IsForbidden(errGot)).To(BeTrue()) + Expect(apierrors.IsForbidden(errGot)).To(BeTrue()) }, }), table.Entry("successfully allows API calls to be made when ServiceAccount has permission", testParameter{ @@ -66,7 +66,7 @@ var _ = Describe("Scoped Client bound to a service account can be used to make A return }, assertFunc: func(errGot error) { - Expect(k8serrors.IsNotFound(errGot)).To(BeTrue()) + Expect(apierrors.IsNotFound(errGot)).To(BeTrue()) }, }), } diff --git a/staging/operator-lifecycle-manager/test/e2e/setup_bare_test.go b/staging/operator-lifecycle-manager/test/e2e/setup_bare_test.go index c3b1b7a284..1151aa47f1 100644 --- a/staging/operator-lifecycle-manager/test/e2e/setup_bare_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/setup_bare_test.go @@ -1,3 +1,4 @@ +//go:build bare // +build bare package e2e @@ -18,7 +19,7 @@ import ( utilclock "k8s.io/apimachinery/pkg/util/clock" "k8s.io/client-go/tools/clientcmd" - v1 "github.com/operator-framework/api/pkg/operators/v1" + operatorsv1 "github.com/operator-framework/api/pkg/operators/v1" "github.com/operator-framework/operator-lifecycle-manager/pkg/api/client" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/catalog" "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/operators/olm" diff --git a/staging/operator-lifecycle-manager/test/e2e/subscription_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/subscription_e2e_test.go index 4b63fc1e6e..03e36a5858 100644 --- a/staging/operator-lifecycle-manager/test/e2e/subscription_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/subscription_e2e_test.go @@ -19,7 +19,7 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" - k8serrors "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" @@ -586,11 +586,11 @@ var _ = Describe("Subscription", func() { // Should eventually GC the CSVs Eventually(func() bool { - return csvExists(crc, csvA.Name) + return csvExists(generatedNamespace.GetName(), crc, csvA.Name) }).Should(BeFalse()) Eventually(func() bool { - return csvExists(crc, csvB.Name) + return csvExists(generatedNamespace.GetName(), crc, csvB.Name) }).Should(BeFalse()) // TODO: check installplans, subscription status, etc @@ -1210,7 +1210,7 @@ var _ = Describe("Subscription", func() { } proxy, getErr := client.Proxies().Get(context.Background(), "cluster", metav1.GetOptions{}) - if k8serrors.IsNotFound(getErr) { + if apierrors.IsNotFound(getErr) { return nil } require.NoError(GinkgoT(), getErr) @@ -2561,7 +2561,7 @@ func init() { func initCatalog(t GinkgoTInterface, namespace string, c operatorclient.ClientInterface, crc versioned.Interface) error { dummyCatalogConfigMap.SetNamespace(namespace) if _, err := c.KubernetesInterface().CoreV1().ConfigMaps(namespace).Create(context.Background(), dummyCatalogConfigMap, metav1.CreateOptions{}); err != nil { - if k8serrors.IsAlreadyExists(err) { + if apierrors.IsAlreadyExists(err) { return fmt.Errorf("E2E bug detected: %v", err) } return err @@ -2569,7 +2569,7 @@ func initCatalog(t GinkgoTInterface, namespace string, c operatorclient.ClientIn dummyCatalogSource.SetNamespace(namespace) if _, err := crc.OperatorsV1alpha1().CatalogSources(namespace).Create(context.Background(), &dummyCatalogSource, metav1.CreateOptions{}); err != nil { - if k8serrors.IsAlreadyExists(err) { + if apierrors.IsAlreadyExists(err) { return fmt.Errorf("E2E bug detected: %v", err) } return err diff --git a/staging/operator-lifecycle-manager/test/e2e/user_defined_sa_test.go b/staging/operator-lifecycle-manager/test/e2e/user_defined_sa_test.go index dd9df90395..13740ab84a 100644 --- a/staging/operator-lifecycle-manager/test/e2e/user_defined_sa_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/user_defined_sa_test.go @@ -13,6 +13,7 @@ import ( "github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/kubernetes/pkg/apis/rbac" "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient" + "github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" @@ -23,8 +24,23 @@ import ( ) var _ = Describe("User defined service account", func() { + var ( + generatedNamespace corev1.Namespace + ) + + BeforeEach(func() { + generatedNamespace = corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: genName("user-defined-sa-e2e-"), + }, + } + Eventually(func() error { + return ctx.Ctx().Client().Create(context.Background(), &generatedNamespace) + }).Should(Succeed()) + }) + AfterEach(func() { - TearDown(testNamespace) + TeardownNamespace(generatedNamespace.GetName()) }) It("with no permission", func() { @@ -32,47 +48,43 @@ var _ = Describe("User defined service account", func() { kubeclient := newKubeClient() crclient := newCRClient() - namespace := genName("scoped-ns-") - _, cleanupNS := newNamespace(kubeclient, namespace) - defer cleanupNS() - // Create a service account, but add no permission to it. saName := genName("scoped-sa-") - _, cleanupSA := newServiceAccount(kubeclient, namespace, saName) + _, cleanupSA := newServiceAccount(kubeclient, generatedNamespace.GetName(), saName) defer cleanupSA() // Add an OperatorGroup and specify the service account. ogName := genName("scoped-og-") - _, cleanupOG := newOperatorGroupWithServiceAccount(crclient, namespace, ogName, saName) + _, cleanupOG := newOperatorGroupWithServiceAccount(crclient, generatedNamespace.GetName(), ogName, saName) defer cleanupOG() permissions := deploymentPermissions() - catsrc, subSpec, catsrcCleanup := newCatalogSource(GinkgoT(), kubeclient, crclient, "scoped", namespace, permissions) + catsrc, subSpec, catsrcCleanup := newCatalogSource(GinkgoT(), kubeclient, crclient, "scoped", generatedNamespace.GetName(), permissions) defer catsrcCleanup() // Ensure that the catalog source is resolved before we create a subscription. - _, err := fetchCatalogSourceOnStatus(crclient, catsrc.GetName(), namespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crclient, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) subscriptionName := genName("scoped-sub-") - cleanupSubscription := createSubscriptionForCatalog(crclient, namespace, subscriptionName, catsrc.GetName(), subSpec.Package, subSpec.Channel, subSpec.StartingCSV, subSpec.InstallPlanApproval) + cleanupSubscription := createSubscriptionForCatalog(crclient, generatedNamespace.GetName(), subscriptionName, catsrc.GetName(), subSpec.Package, subSpec.Channel, subSpec.StartingCSV, subSpec.InstallPlanApproval) defer cleanupSubscription() // Wait until an install plan is created. - subscription, err := fetchSubscription(crclient, namespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crclient, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) // We expect the InstallPlan to be in status: Failed. ipName := subscription.Status.Install.Name ipPhaseCheckerFunc := buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseFailed) - ipGot, err := fetchInstallPlanWithNamespace(GinkgoT(), crclient, ipName, namespace, ipPhaseCheckerFunc) + ipGot, err := fetchInstallPlanWithNamespace(GinkgoT(), crclient, ipName, generatedNamespace.GetName(), ipPhaseCheckerFunc) require.NoError(GinkgoT(), err) conditionGot := mustHaveCondition(GinkgoT(), ipGot, v1alpha1.InstallPlanInstalled) assert.Equal(GinkgoT(), corev1.ConditionFalse, conditionGot.Status) assert.Equal(GinkgoT(), v1alpha1.InstallPlanReasonComponentFailed, conditionGot.Reason) - assert.Contains(GinkgoT(), conditionGot.Message, fmt.Sprintf("is forbidden: User \"system:serviceaccount:%s:%s\" cannot create resource", namespace, saName)) + assert.Contains(GinkgoT(), conditionGot.Message, fmt.Sprintf("is forbidden: User \"system:serviceaccount:%s:%s\" cannot create resource", generatedNamespace.GetName(), saName)) // Verify that all step resources are in Unknown state. for _, step := range ipGot.Status.Plan { @@ -85,43 +97,39 @@ var _ = Describe("User defined service account", func() { kubeclient := newKubeClient() crclient := newCRClient() - namespace := genName("scoped-ns-") - _, cleanupNS := newNamespace(kubeclient, namespace) - defer cleanupNS() - // Create a service account, add enough permission to it so that operator install is successful. saName := genName("scoped-sa") - _, cleanupSA := newServiceAccount(kubeclient, namespace, saName) + _, cleanupSA := newServiceAccount(kubeclient, generatedNamespace.GetName(), saName) defer cleanupSA() - cleanupPerm := grantPermission(GinkgoT(), kubeclient, namespace, saName) + cleanupPerm := grantPermission(GinkgoT(), kubeclient, generatedNamespace.GetName(), saName) defer cleanupPerm() // Add an OperatorGroup and specify the service account. ogName := genName("scoped-og-") - _, cleanupOG := newOperatorGroupWithServiceAccount(crclient, namespace, ogName, saName) + _, cleanupOG := newOperatorGroupWithServiceAccount(crclient, generatedNamespace.GetName(), ogName, saName) defer cleanupOG() permissions := deploymentPermissions() - catsrc, subSpec, catsrcCleanup := newCatalogSource(GinkgoT(), kubeclient, crclient, "scoped", namespace, permissions) + catsrc, subSpec, catsrcCleanup := newCatalogSource(GinkgoT(), kubeclient, crclient, "scoped", generatedNamespace.GetName(), permissions) defer catsrcCleanup() // Ensure that the catalog source is resolved before we create a subscription. - _, err := fetchCatalogSourceOnStatus(crclient, catsrc.GetName(), namespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crclient, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) subscriptionName := genName("scoped-sub-") - cleanupSubscription := createSubscriptionForCatalog(crclient, namespace, subscriptionName, catsrc.GetName(), subSpec.Package, subSpec.Channel, subSpec.StartingCSV, subSpec.InstallPlanApproval) + cleanupSubscription := createSubscriptionForCatalog(crclient, generatedNamespace.GetName(), subscriptionName, catsrc.GetName(), subSpec.Package, subSpec.Channel, subSpec.StartingCSV, subSpec.InstallPlanApproval) defer cleanupSubscription() // Wait until an install plan is created. - subscription, err := fetchSubscription(crclient, namespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crclient, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) // We expect the InstallPlan to be in status: Complete. ipName := subscription.Status.Install.Name ipPhaseCheckerFunc := buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete) - ipGot, err := fetchInstallPlanWithNamespace(GinkgoT(), crclient, ipName, namespace, ipPhaseCheckerFunc) + ipGot, err := fetchInstallPlanWithNamespace(GinkgoT(), crclient, ipName, generatedNamespace.GetName(), ipPhaseCheckerFunc) require.NoError(GinkgoT(), err) conditionGot := mustHaveCondition(GinkgoT(), ipGot, v1alpha1.InstallPlanInstalled) @@ -141,50 +149,46 @@ var _ = Describe("User defined service account", func() { kubeclient := newKubeClient() crclient := newCRClient() - namespace := genName("scoped-ns-") - _, cleanupNS := newNamespace(kubeclient, namespace) - defer cleanupNS() - // Create a service account, but add no permission to it. saName := genName("scoped-sa-") - _, cleanupSA := newServiceAccount(kubeclient, namespace, saName) + _, cleanupSA := newServiceAccount(kubeclient, generatedNamespace.GetName(), saName) defer cleanupSA() // Add an OperatorGroup and specify the service account. ogName := genName("scoped-og-") - _, cleanupOG := newOperatorGroupWithServiceAccount(crclient, namespace, ogName, saName) + _, cleanupOG := newOperatorGroupWithServiceAccount(crclient, generatedNamespace.GetName(), ogName, saName) defer cleanupOG() permissions := deploymentPermissions() - catsrc, subSpec, catsrcCleanup := newCatalogSource(GinkgoT(), kubeclient, crclient, "scoped", namespace, permissions) + catsrc, subSpec, catsrcCleanup := newCatalogSource(GinkgoT(), kubeclient, crclient, "scoped", generatedNamespace.GetName(), permissions) defer catsrcCleanup() // Ensure that the catalog source is resolved before we create a subscription. - _, err := fetchCatalogSourceOnStatus(crclient, catsrc.GetName(), namespace, catalogSourceRegistryPodSynced) + _, err := fetchCatalogSourceOnStatus(crclient, catsrc.GetName(), generatedNamespace.GetName(), catalogSourceRegistryPodSynced) require.NoError(GinkgoT(), err) subscriptionName := genName("scoped-sub-") - cleanupSubscription := createSubscriptionForCatalog(crclient, namespace, subscriptionName, catsrc.GetName(), subSpec.Package, subSpec.Channel, subSpec.StartingCSV, subSpec.InstallPlanApproval) + cleanupSubscription := createSubscriptionForCatalog(crclient, generatedNamespace.GetName(), subscriptionName, catsrc.GetName(), subSpec.Package, subSpec.Channel, subSpec.StartingCSV, subSpec.InstallPlanApproval) defer cleanupSubscription() // Wait until an install plan is created. - subscription, err := fetchSubscription(crclient, namespace, subscriptionName, subscriptionHasInstallPlanChecker) + subscription, err := fetchSubscription(crclient, generatedNamespace.GetName(), subscriptionName, subscriptionHasInstallPlanChecker) require.NoError(GinkgoT(), err) require.NotNil(GinkgoT(), subscription) // We expect the InstallPlan to be in status: Failed. ipNameOld := subscription.Status.InstallPlanRef.Name ipPhaseCheckerFunc := buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseFailed) - ipGotOld, err := fetchInstallPlanWithNamespace(GinkgoT(), crclient, ipNameOld, namespace, ipPhaseCheckerFunc) + ipGotOld, err := fetchInstallPlanWithNamespace(GinkgoT(), crclient, ipNameOld, generatedNamespace.GetName(), ipPhaseCheckerFunc) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), v1alpha1.InstallPlanPhaseFailed, ipGotOld.Status.Phase) // Grant permission now and this should trigger an retry of InstallPlan. - cleanupPerm := grantPermission(GinkgoT(), kubeclient, namespace, saName) + cleanupPerm := grantPermission(GinkgoT(), kubeclient, generatedNamespace.GetName(), saName) defer cleanupPerm() ipPhaseCheckerFunc = buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseComplete) - ipGotNew, err := fetchInstallPlanWithNamespace(GinkgoT(), crclient, ipNameOld, namespace, ipPhaseCheckerFunc) + ipGotNew, err := fetchInstallPlanWithNamespace(GinkgoT(), crclient, ipNameOld, generatedNamespace.GetName(), ipPhaseCheckerFunc) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), v1alpha1.InstallPlanPhaseComplete, ipGotNew.Status.Phase) }) diff --git a/staging/operator-lifecycle-manager/test/e2e/util.go b/staging/operator-lifecycle-manager/test/e2e/util.go index 170cea7995..fe4c663ba1 100644 --- a/staging/operator-lifecycle-manager/test/e2e/util.go +++ b/staging/operator-lifecycle-manager/test/e2e/util.go @@ -509,7 +509,11 @@ func buildCatalogSourceCleanupFunc(crc versioned.Interface, namespace string, ca Expect(err).ToNot(HaveOccurred()) Eventually(func() (bool, error) { - fetched, err := newKubeClient().KubernetesInterface().CoreV1().Pods(catalogSource.GetNamespace()).List(context.Background(), metav1.ListOptions{LabelSelector: "olm.catalogSource=" + catalogSource.GetName()}) + listOpts := metav1.ListOptions{ + LabelSelector: "olm.catalogSource=" + catalogSource.GetName(), + FieldSelector: "status.phase=Running", + } + fetched, err := newKubeClient().KubernetesInterface().CoreV1().Pods(catalogSource.GetNamespace()).List(context.Background(), listOpts) if err != nil { return false, err } @@ -959,6 +963,12 @@ func HavePhase(goal operatorsv1alpha1.InstallPlanPhase) gtypes.GomegaMatcher { }, Equal(goal)) } +func CSVHasPhase(goal operatorsv1alpha1.ClusterServiceVersionPhase) gtypes.GomegaMatcher { + return WithTransform(func(csv *operatorsv1alpha1.ClusterServiceVersion) operatorsv1alpha1.ClusterServiceVersionPhase { + return csv.Status.Phase + }, Equal(goal)) +} + func HaveMessage(goal string) gtypes.GomegaMatcher { return WithTransform(func(plan *operatorsv1alpha1.InstallPlan) string { return plan.Status.Message diff --git a/staging/operator-lifecycle-manager/test/e2e/webhook_e2e_test.go b/staging/operator-lifecycle-manager/test/e2e/webhook_e2e_test.go index 125dd1a79a..66f0163229 100644 --- a/staging/operator-lifecycle-manager/test/e2e/webhook_e2e_test.go +++ b/staging/operator-lifecycle-manager/test/e2e/webhook_e2e_test.go @@ -8,6 +8,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/operator-framework/operator-lifecycle-manager/test/e2e/ctx" "github.com/stretchr/testify/require" admissionregistrationv1 "k8s.io/api/admissionregistration/v1" corev1 "k8s.io/api/core/v1" @@ -30,39 +31,34 @@ const ( ) var _ = Describe("CSVs with a Webhook", func() { - var c operatorclient.ClientInterface - var crc versioned.Interface - var namespace *corev1.Namespace - var nsCleanupFunc cleanupFunc - var nsLabels map[string]string + + var ( + generatedNamespace corev1.Namespace + c operatorclient.ClientInterface + crc versioned.Interface + nsLabels map[string]string + ) + BeforeEach(func() { c = newKubeClient() crc = newCRClient() - nsLabels = map[string]string{ - "foo": "bar", - } - namespace = &corev1.Namespace{ + generatedNamespace = corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ - Name: genName("webhook-test-"), - Labels: nsLabels, + Name: genName("webhook-e2e-"), + Labels: map[string]string{ + "foo": "bar", + }, }, } - - var err error - namespace, err = c.KubernetesInterface().CoreV1().Namespaces().Create(context.TODO(), namespace, metav1.CreateOptions{}) - Expect(err).Should(BeNil()) - Expect(namespace).ShouldNot(BeNil()) - - nsCleanupFunc = func() { - err := c.KubernetesInterface().CoreV1().Namespaces().Delete(context.TODO(), namespace.GetName(), metav1.DeleteOptions{}) - Expect(err).Should(BeNil()) - } + Eventually(func() error { + return ctx.Ctx().Client().Create(context.Background(), &generatedNamespace) + }).Should(Succeed()) }) + AfterEach(func() { - if nsCleanupFunc != nil { - nsCleanupFunc() - } + TeardownNamespace(generatedNamespace.GetName()) }) + When("Installed in an OperatorGroup that defines a selector", func() { var cleanupCSV cleanupFunc var ogSelector *metav1.LabelSelector @@ -71,8 +67,8 @@ var _ = Describe("CSVs with a Webhook", func() { MatchLabels: nsLabels, } - og := newOperatorGroup(namespace.Name, genName("selector-og-"), nil, ogSelector, nil, false) - _, err := crc.OperatorsV1().OperatorGroups(namespace.Name).Create(context.TODO(), og, metav1.CreateOptions{}) + og := newOperatorGroup(generatedNamespace.GetName(), genName("selector-og-"), nil, ogSelector, nil, false) + _, err := crc.OperatorsV1().OperatorGroups(generatedNamespace.GetName()).Create(context.TODO(), og, metav1.CreateOptions{}) Expect(err).Should(BeNil()) }) AfterEach(func() { @@ -91,12 +87,12 @@ var _ = Describe("CSVs with a Webhook", func() { SideEffects: &sideEffect, } - csv := createCSVWithWebhook(namespace.GetName(), webhook) + csv := createCSVWithWebhook(generatedNamespace.GetName(), webhook) var err error - cleanupCSV, err = createCSV(c, crc, csv, namespace.Name, false, false) + cleanupCSV, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).Should(BeNil()) - _, err = fetchCSV(crc, csv.Name, namespace.Name, csvSucceededChecker) + _, err = fetchCSV(crc, csv.Name, generatedNamespace.GetName(), csvSucceededChecker) Expect(err).Should(BeNil()) actualWebhook, err := getWebhookWithGenerateName(c, webhook.GenerateName) @@ -109,9 +105,9 @@ var _ = Describe("CSVs with a Webhook", func() { var cleanupCSV cleanupFunc var og *v1.OperatorGroup BeforeEach(func() { - og = newOperatorGroup(namespace.Name, genName("single-namespace-og-"), nil, nil, []string{namespace.Name}, false) + og = newOperatorGroup(generatedNamespace.GetName(), genName("single-namespace-og-"), nil, nil, []string{generatedNamespace.GetName()}, false) var err error - og, err = crc.OperatorsV1().OperatorGroups(namespace.Name).Create(context.TODO(), og, metav1.CreateOptions{}) + og, err = crc.OperatorsV1().OperatorGroups(generatedNamespace.GetName()).Create(context.TODO(), og, metav1.CreateOptions{}) Expect(err).Should(BeNil()) }) AfterEach(func() { @@ -130,12 +126,12 @@ var _ = Describe("CSVs with a Webhook", func() { SideEffects: &sideEffect, } - csv := createCSVWithWebhook(namespace.GetName(), webhook) + csv := createCSVWithWebhook(generatedNamespace.GetName(), webhook) var err error - cleanupCSV, err = createCSV(c, crc, csv, namespace.Name, false, false) + cleanupCSV, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).Should(BeNil()) - _, err = fetchCSV(crc, csv.Name, namespace.Name, csvSucceededChecker) + _, err = fetchCSV(crc, csv.Name, generatedNamespace.GetName(), csvSucceededChecker) Expect(err).Should(BeNil()) actualWebhook, err := getWebhookWithGenerateName(c, webhook.GenerateName) @@ -153,13 +149,13 @@ var _ = Describe("CSVs with a Webhook", func() { // Ensure that changes to the WebhookDescription within the CSV trigger an update to on cluster resources changedGenerateName := webhookName + "-changed" Eventually(func() error { - existingCSV, err := crc.OperatorsV1alpha1().ClusterServiceVersions(namespace.Name).Get(context.TODO(), csv.GetName(), metav1.GetOptions{}) + existingCSV, err := crc.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Get(context.TODO(), csv.GetName(), metav1.GetOptions{}) if err != nil { return err } existingCSV.Spec.WebhookDefinitions[0].GenerateName = changedGenerateName - existingCSV, err = crc.OperatorsV1alpha1().ClusterServiceVersions(namespace.Name).Update(context.TODO(), existingCSV, metav1.UpdateOptions{}) + existingCSV, err = crc.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Update(context.TODO(), existingCSV, metav1.UpdateOptions{}) return err }, time.Minute, 5*time.Second).Should(Succeed()) Eventually(func() bool { @@ -184,39 +180,39 @@ var _ = Describe("CSVs with a Webhook", func() { AdmissionReviewVersions: []string{"v1beta1", "v1"}, SideEffects: &sideEffect, } - csv := createCSVWithWebhook(namespace.GetName(), webhook) + csv := createCSVWithWebhook(generatedNamespace.GetName(), webhook) var err error - cleanupCSV, err = createCSV(c, crc, csv, namespace.GetName(), false, false) + cleanupCSV, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).Should(BeNil()) - _, err = fetchCSV(crc, csv.Name, namespace.GetName(), csvSucceededChecker) + _, err = fetchCSV(crc, csv.Name, generatedNamespace.GetName(), csvSucceededChecker) Expect(err).Should(BeNil()) // Get the existing secret webhookSecretName := webhook.DeploymentName + "-service-cert" - existingSecret, err := c.KubernetesInterface().CoreV1().Secrets(namespace.GetName()).Get(context.TODO(), webhookSecretName, metav1.GetOptions{}) + existingSecret, err := c.KubernetesInterface().CoreV1().Secrets(generatedNamespace.GetName()).Get(context.TODO(), webhookSecretName, metav1.GetOptions{}) require.NoError(GinkgoT(), err) // Modify the phase Eventually(func() bool { - fetchedCSV, err := crc.OperatorsV1alpha1().ClusterServiceVersions(namespace.GetName()).Get(context.TODO(), csv.GetName(), metav1.GetOptions{}) + fetchedCSV, err := crc.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).Get(context.TODO(), csv.GetName(), metav1.GetOptions{}) if err != nil { return false } fetchedCSV.Status.Phase = operatorsv1alpha1.CSVPhasePending - _, err = crc.OperatorsV1alpha1().ClusterServiceVersions(namespace.GetName()).UpdateStatus(context.TODO(), fetchedCSV, metav1.UpdateOptions{}) + _, err = crc.OperatorsV1alpha1().ClusterServiceVersions(generatedNamespace.GetName()).UpdateStatus(context.TODO(), fetchedCSV, metav1.UpdateOptions{}) return err == nil }).Should(BeTrue(), "Unable to set CSV phase to Pending") // Wait for webhook-operator to succeed - _, err = awaitCSV(crc, namespace.GetName(), csv.GetName(), csvSucceededChecker) + _, err = awaitCSV(crc, generatedNamespace.GetName(), csv.GetName(), csvSucceededChecker) require.NoError(GinkgoT(), err) // Get the updated secret - updatedSecret, err := c.KubernetesInterface().CoreV1().Secrets(namespace.GetName()).Get(context.TODO(), webhookSecretName, metav1.GetOptions{}) + updatedSecret, err := c.KubernetesInterface().CoreV1().Secrets(generatedNamespace.GetName()).Get(context.TODO(), webhookSecretName, metav1.GetOptions{}) require.NoError(GinkgoT(), err) require.Equal(GinkgoT(), existingSecret.GetAnnotations()[install.OLMCAHashAnnotationKey], updatedSecret.GetAnnotations()[install.OLMCAHashAnnotationKey]) @@ -233,13 +229,13 @@ var _ = Describe("CSVs with a Webhook", func() { SideEffects: &sideEffect, } - csv := createCSVWithWebhook(namespace.GetName(), webhook) + csv := createCSVWithWebhook(generatedNamespace.GetName(), webhook) csv.Spec.WebhookDefinitions = append(csv.Spec.WebhookDefinitions, webhook) var err error - cleanupCSV, err = createCSV(c, crc, csv, namespace.Name, false, false) + cleanupCSV, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).Should(BeNil()) - _, err = fetchCSV(crc, csv.Name, namespace.Name, csvFailedChecker) + _, err = fetchCSV(crc, csv.Name, generatedNamespace.GetName(), csvFailedChecker) Expect(err).Should(BeNil()) }) It("Fails if the webhooks intercepts all resources", func() { @@ -263,13 +259,13 @@ var _ = Describe("CSVs with a Webhook", func() { }, } - csv := createCSVWithWebhook(namespace.GetName(), webhook) + csv := createCSVWithWebhook(generatedNamespace.GetName(), webhook) var err error - cleanupCSV, err = createCSV(c, crc, csv, namespace.Name, false, false) + cleanupCSV, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).Should(BeNil()) - failedCSV, err := fetchCSV(crc, csv.Name, namespace.Name, csvFailedChecker) + failedCSV, err := fetchCSV(crc, csv.Name, generatedNamespace.GetName(), csvFailedChecker) Expect(err).Should(BeNil()) Expect(failedCSV.Status.Message).Should(Equal("webhook rules cannot include all groups")) }) @@ -294,13 +290,13 @@ var _ = Describe("CSVs with a Webhook", func() { }, } - csv := createCSVWithWebhook(namespace.GetName(), webhook) + csv := createCSVWithWebhook(generatedNamespace.GetName(), webhook) var err error - cleanupCSV, err = createCSV(c, crc, csv, namespace.Name, false, false) + cleanupCSV, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).Should(BeNil()) - failedCSV, err := fetchCSV(crc, csv.Name, namespace.Name, csvFailedChecker) + failedCSV, err := fetchCSV(crc, csv.Name, generatedNamespace.GetName(), csvFailedChecker) Expect(err).Should(BeNil()) Expect(failedCSV.Status.Message).Should(Equal("webhook rules cannot include the OLM group")) }) @@ -325,13 +321,13 @@ var _ = Describe("CSVs with a Webhook", func() { }, } - csv := createCSVWithWebhook(namespace.GetName(), webhook) + csv := createCSVWithWebhook(generatedNamespace.GetName(), webhook) var err error - cleanupCSV, err = createCSV(c, crc, csv, namespace.Name, false, false) + cleanupCSV, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).Should(BeNil()) - failedCSV, err := fetchCSV(crc, csv.Name, namespace.Name, csvFailedChecker) + failedCSV, err := fetchCSV(crc, csv.Name, generatedNamespace.GetName(), csvFailedChecker) Expect(err).Should(BeNil()) Expect(failedCSV.Status.Message).Should(Equal("webhook rules cannot include MutatingWebhookConfiguration or ValidatingWebhookConfiguration resources")) }) @@ -358,13 +354,13 @@ var _ = Describe("CSVs with a Webhook", func() { }, } - csv := createCSVWithWebhook(namespace.GetName(), webhook) + csv := createCSVWithWebhook(generatedNamespace.GetName(), webhook) var err error - cleanupCSV, err = createCSV(c, crc, csv, namespace.Name, false, false) + cleanupCSV, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).Should(BeNil()) - _, err = fetchCSV(crc, csv.Name, namespace.Name, csvSucceededChecker) + _, err = fetchCSV(crc, csv.Name, generatedNamespace.GetName(), csvSucceededChecker) Expect(err).Should(BeNil()) }) It("Can be installed and upgraded successfully", func() { @@ -390,13 +386,13 @@ var _ = Describe("CSVs with a Webhook", func() { }, } - csv := createCSVWithWebhook(namespace.GetName(), webhook) + csv := createCSVWithWebhook(generatedNamespace.GetName(), webhook) - _, err := createCSV(c, crc, csv, namespace.Name, false, false) + _, err := createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).Should(BeNil()) // cleanup by upgrade - _, err = fetchCSV(crc, csv.Name, namespace.Name, csvSucceededChecker) + _, err = fetchCSV(crc, csv.Name, generatedNamespace.GetName(), csvSucceededChecker) Expect(err).Should(BeNil()) _, err = getWebhookWithGenerateName(c, webhook.GenerateName) @@ -408,10 +404,10 @@ var _ = Describe("CSVs with a Webhook", func() { previousWebhookName := webhook.GenerateName webhook.GenerateName = "webhook2.test.com" csv.Spec.WebhookDefinitions[0] = webhook - cleanupCSV, err = createCSV(c, crc, csv, namespace.Name, false, false) + cleanupCSV, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).Should(BeNil()) - _, err = fetchCSV(crc, csv.GetName(), namespace.Name, csvSucceededChecker) + _, err = fetchCSV(crc, csv.GetName(), generatedNamespace.GetName(), csvSucceededChecker) Expect(err).Should(BeNil()) _, err = getWebhookWithGenerateName(c, webhook.GenerateName) @@ -419,7 +415,7 @@ var _ = Describe("CSVs with a Webhook", func() { // Make sure old resources are cleaned up. Eventually(func() bool { - return csvExists(crc, csv.Spec.Replaces) + return csvExists(generatedNamespace.GetName(), crc, csv.Spec.Replaces) }).Should(BeFalse()) // Wait until previous webhook is cleaned up @@ -446,13 +442,13 @@ var _ = Describe("CSVs with a Webhook", func() { SideEffects: &sideEffect, } - csv := createCSVWithWebhook(namespace.GetName(), webhook) + csv := createCSVWithWebhook(generatedNamespace.GetName(), webhook) var err error - cleanupCSV, err = createCSV(c, crc, csv, namespace.Name, false, false) + cleanupCSV, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).Should(BeNil()) - fetchedCSV, err := fetchCSV(crc, csv.Name, namespace.Name, csvSucceededChecker) + fetchedCSV, err := fetchCSV(crc, csv.Name, generatedNamespace.GetName(), csvSucceededChecker) Expect(err).Should(BeNil()) actualWebhook, err := getWebhookWithGenerateName(c, webhook.GenerateName) @@ -461,7 +457,7 @@ var _ = Describe("CSVs with a Webhook", func() { oldWebhookCABundle := actualWebhook.Webhooks[0].ClientConfig.CABundle // Get the deployment - dep, err := c.KubernetesInterface().AppsV1().Deployments(namespace.Name).Get(context.TODO(), csv.Spec.WebhookDefinitions[0].DeploymentName, metav1.GetOptions{}) + dep, err := c.KubernetesInterface().AppsV1().Deployments(generatedNamespace.GetName()).Get(context.TODO(), csv.Spec.WebhookDefinitions[0].DeploymentName, metav1.GetOptions{}) Expect(err).Should(BeNil()) //Store the ca sha annotation @@ -476,9 +472,9 @@ var _ = Describe("CSVs with a Webhook", func() { return nil })).Should(Succeed()) - _, err = fetchCSV(crc, csv.Name, namespace.Name, func(csv *operatorsv1alpha1.ClusterServiceVersion) bool { + _, err = fetchCSV(crc, csv.Name, generatedNamespace.GetName(), func(csv *operatorsv1alpha1.ClusterServiceVersion) bool { // Should create deployment - dep, err = c.GetDeployment(namespace.Name, csv.Spec.WebhookDefinitions[0].DeploymentName) + dep, err = c.GetDeployment(generatedNamespace.GetName(), csv.Spec.WebhookDefinitions[0].DeploymentName) if err != nil { return false } @@ -509,8 +505,8 @@ var _ = Describe("CSVs with a Webhook", func() { When("Installed in a Global OperatorGroup", func() { var cleanupCSV cleanupFunc BeforeEach(func() { - og := newOperatorGroup(namespace.Name, genName("global-og-"), nil, nil, []string{}, false) - og, err := crc.OperatorsV1().OperatorGroups(namespace.Name).Create(context.TODO(), og, metav1.CreateOptions{}) + og := newOperatorGroup(generatedNamespace.GetName(), genName("global-og-"), nil, nil, []string{}, false) + og, err := crc.OperatorsV1().OperatorGroups(generatedNamespace.GetName()).Create(context.TODO(), og, metav1.CreateOptions{}) Expect(err).Should(BeNil()) }) AfterEach(func() { @@ -529,13 +525,13 @@ var _ = Describe("CSVs with a Webhook", func() { SideEffects: &sideEffect, } - csv := createCSVWithWebhook(namespace.GetName(), webhook) + csv := createCSVWithWebhook(generatedNamespace.GetName(), webhook) var err error - cleanupCSV, err = createCSV(c, crc, csv, namespace.Name, false, false) + cleanupCSV, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).Should(BeNil()) - _, err = fetchCSV(crc, csv.Name, namespace.Name, csvSucceededChecker) + _, err = fetchCSV(crc, csv.Name, generatedNamespace.GetName(), csvSucceededChecker) Expect(err).Should(BeNil()) actualWebhook, err := getWebhookWithGenerateName(c, webhook.GenerateName) Expect(err).Should(BeNil()) @@ -588,7 +584,7 @@ var _ = Describe("CSVs with a Webhook", func() { SideEffects: &sideEffect, } - csv := createCSVWithWebhook(namespace.GetName(), webhook) + csv := createCSVWithWebhook(generatedNamespace.GetName(), webhook) csv.Namespace = namespace1.GetName() var cleanupCSV cleanupFunc @@ -636,6 +632,9 @@ var _ = Describe("CSVs with a Webhook", func() { var cleanupCatSrc cleanupFunc var cleanupSubscription cleanupFunc BeforeEach(func() { + og := newOperatorGroup(generatedNamespace.GetName(), genName("og-"), nil, nil, []string{}, false) + _, err := crc.OperatorsV1().OperatorGroups(generatedNamespace.GetName()).Create(context.TODO(), og, metav1.CreateOptions{}) + Expect(err).Should(BeNil()) // Create a catalogSource which has the webhook-operator sourceName := genName("catalog-") @@ -652,7 +651,7 @@ var _ = Describe("CSVs with a Webhook", func() { }, ObjectMeta: metav1.ObjectMeta{ Name: sourceName, - Namespace: testNamespace, + Namespace: generatedNamespace.GetName(), }, Spec: operatorsv1alpha1.CatalogSourceSpec{ SourceType: operatorsv1alpha1.SourceTypeGrpc, @@ -661,7 +660,7 @@ var _ = Describe("CSVs with a Webhook", func() { } crc := newCRClient() - source, err := crc.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(context.TODO(), source, metav1.CreateOptions{}) + source, err = crc.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Create(context.TODO(), source, metav1.CreateOptions{}) require.NoError(GinkgoT(), err) cleanupCatSrc = func() { require.NoError(GinkgoT(), crc.OperatorsV1alpha1().CatalogSources(source.GetNamespace()).Delete(context.TODO(), source.GetName(), metav1.DeleteOptions{})) @@ -673,14 +672,14 @@ var _ = Describe("CSVs with a Webhook", func() { // Create a Subscription for the webhook-operator subscriptionName := genName("sub-") - cleanupSubscription := createSubscriptionForCatalog(crc, testNamespace, subscriptionName, source.GetName(), packageName, channelName, "", operatorsv1alpha1.ApprovalAutomatic) + cleanupSubscription := createSubscriptionForCatalog(crc, source.GetNamespace(), subscriptionName, source.GetName(), packageName, channelName, "", operatorsv1alpha1.ApprovalAutomatic) defer cleanupSubscription() // Wait for webhook-operator v2 csv to succeed - csv, err := awaitCSV(crc, testNamespace, "webhook-operator.v0.0.1", csvSucceededChecker) + csv, err := awaitCSV(crc, source.GetNamespace(), "webhook-operator.v0.0.1", csvSucceededChecker) require.NoError(GinkgoT(), err) - cleanupCSV = buildCSVCleanupFunc(c, crc, *csv, testNamespace, true, true) + cleanupCSV = buildCSVCleanupFunc(c, crc, *csv, source.GetNamespace(), true, true) }) AfterEach(func() { if cleanupCSV != nil { @@ -700,7 +699,7 @@ var _ = Describe("CSVs with a Webhook", func() { "apiVersion": "webhook.operators.coreos.io/v1", "kind": "webhooktests", "metadata": map[string]interface{}{ - "namespace": testNamespace, + "namespace": generatedNamespace.GetName(), "name": "my-cr-1", }, "spec": map[string]interface{}{ @@ -723,7 +722,7 @@ var _ = Describe("CSVs with a Webhook", func() { "apiVersion": "webhook.operators.coreos.io/v1", "kind": "webhooktests", "metadata": map[string]interface{}{ - "namespace": testNamespace, + "namespace": generatedNamespace.GetName(), "name": "my-cr-1", }, "spec": map[string]interface{}{ @@ -731,12 +730,12 @@ var _ = Describe("CSVs with a Webhook", func() { }, }, } - crCleanupFunc, err := createCR(c, validCR, "webhook.operators.coreos.io", "v1", testNamespace, "webhooktests", "my-cr-1") + crCleanupFunc, err := createCR(c, validCR, "webhook.operators.coreos.io", "v1", generatedNamespace.GetName(), "webhooktests", "my-cr-1") defer crCleanupFunc() require.NoError(GinkgoT(), err, "The valid CR should have been approved by the validating webhook") // Check that you can get v1 of the webhooktest cr - v1UnstructuredObject, err := c.GetCustomResource("webhook.operators.coreos.io", "v1", testNamespace, "webhooktests", "my-cr-1") + v1UnstructuredObject, err := c.GetCustomResource("webhook.operators.coreos.io", "v1", generatedNamespace.GetName(), "webhooktests", "my-cr-1") require.NoError(GinkgoT(), err, "Unable to get the v1 of the valid CR") v1Object := v1UnstructuredObject.Object v1Spec, ok := v1Object["spec"].(map[string]interface{}) @@ -750,7 +749,7 @@ var _ = Describe("CSVs with a Webhook", func() { require.True(GinkgoT(), v1SpecValid, "The validating webhook should have required that the CR's spec.valid field is true") // Check that you can get v2 of the webhooktest cr - v2UnstructuredObject, err := c.GetCustomResource("webhook.operators.coreos.io", "v2", testNamespace, "webhooktests", "my-cr-1") + v2UnstructuredObject, err := c.GetCustomResource("webhook.operators.coreos.io", "v2", generatedNamespace.GetName(), "webhooktests", "my-cr-1") require.NoError(GinkgoT(), err, "Unable to get the v2 of the valid CR") v2Object := v2UnstructuredObject.Object v2Spec := v2Object["spec"].(map[string]interface{}) @@ -769,8 +768,8 @@ var _ = Describe("CSVs with a Webhook", func() { var cleanupCSV cleanupFunc BeforeEach(func() { // global operator group - og := newOperatorGroup(namespace.Name, genName("global-og-"), nil, nil, []string{}, false) - og, err := crc.OperatorsV1().OperatorGroups(namespace.Name).Create(context.TODO(), og, metav1.CreateOptions{}) + og := newOperatorGroup(generatedNamespace.GetName(), genName("global-og-"), nil, nil, []string{}, false) + og, err := crc.OperatorsV1().OperatorGroups(generatedNamespace.GetName()).Create(context.TODO(), og, metav1.CreateOptions{}) Expect(err).Should(BeNil()) }) AfterEach(func() { @@ -808,13 +807,13 @@ var _ = Describe("CSVs with a Webhook", func() { ownedCRDDescs := make([]operatorsv1alpha1.CRDDescription, 0) // create CSV - csv := createCSVWithWebhookAndCrds(namespace.GetName(), webhook, ownedCRDDescs) + csv := createCSVWithWebhookAndCrds(generatedNamespace.GetName(), webhook, ownedCRDDescs) var err error - cleanupCSV, err = createCSV(c, crc, csv, namespace.Name, false, false) + cleanupCSV, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).Should(BeNil()) - _, err = fetchCSV(crc, csv.Name, namespace.Name, csvSucceededChecker) + _, err = fetchCSV(crc, csv.Name, generatedNamespace.GetName(), csvSucceededChecker) Expect(err).Should(BeNil()) actualWebhook, err := getWebhookWithGenerateName(c, webhook.GenerateName) Expect(err).Should(BeNil()) @@ -871,13 +870,13 @@ var _ = Describe("CSVs with a Webhook", func() { ownedCRDDescs = append(ownedCRDDescs, operatorsv1alpha1.CRDDescription{Name: crdA.GetName(), Version: crdA.Spec.Versions[0].Name, Kind: crdA.Spec.Names.Kind}) // create CSV - csv := createCSVWithWebhookAndCrdsAndInvalidInstallModes(namespace.GetName(), webhook, ownedCRDDescs) + csv := createCSVWithWebhookAndCrdsAndInvalidInstallModes(generatedNamespace.GetName(), webhook, ownedCRDDescs) var err error - cleanupCSV, err = createCSV(c, crc, csv, namespace.Name, false, false) + cleanupCSV, err = createCSV(c, crc, csv, generatedNamespace.GetName(), false, false) Expect(err).Should(BeNil()) - _, err = fetchCSV(crc, csv.Name, namespace.Name, csvSucceededChecker) + _, err = fetchCSV(crc, csv.Name, generatedNamespace.GetName(), csvSucceededChecker) Expect(err).Should(BeNil()) actualWebhook, err := getWebhookWithGenerateName(c, webhook.GenerateName) Expect(err).Should(BeNil())