diff --git a/api/v1/clusterextension_types.go b/api/v1/clusterextension_types.go index e331ec63e1..4df1bfcba4 100644 --- a/api/v1/clusterextension_types.go +++ b/api/v1/clusterextension_types.go @@ -102,8 +102,6 @@ type ClusterExtensionSpec struct { // ClusterExtension's manifests. Values can be specified inline. // // config is optional. When not specified, the default configuration of the resolved bundle will be used. - // - // // +optional Config *ClusterExtensionConfig `json:"config,omitempty"` } diff --git a/docs/api-reference/olmv1-api-reference.md b/docs/api-reference/olmv1-api-reference.md index 1b1ad66565..61998c612e 100644 --- a/docs/api-reference/olmv1-api-reference.md +++ b/docs/api-reference/olmv1-api-reference.md @@ -343,7 +343,7 @@ _Appears in:_ | `serviceAccount` _[ServiceAccountReference](#serviceaccountreference)_ | serviceAccount is a reference to a ServiceAccount used to perform all interactions
with the cluster that are required to manage the extension.
The ServiceAccount must be configured with the necessary permissions to perform these interactions.
The ServiceAccount must exist in the namespace referenced in the spec.
serviceAccount is required. | | Required: \{\}
| | `source` _[SourceConfig](#sourceconfig)_ | source is a required field which selects the installation source of content
for this ClusterExtension. Selection is performed by setting the sourceType.

Catalog is currently the only implemented sourceType, and setting the
sourcetype to "Catalog" requires the catalog field to also be defined.

Below is a minimal example of a source definition (in yaml):

source:
sourceType: Catalog
catalog:
packageName: example-package | | Required: \{\}
| | `install` _[ClusterExtensionInstallConfig](#clusterextensioninstallconfig)_ | install is an optional field used to configure the installation options
for the ClusterExtension such as the pre-flight check configuration. | | | -| `config` _[ClusterExtensionConfig](#clusterextensionconfig)_ | config contains optional configuration values applied during rendering of the
ClusterExtension's manifests. Values can be specified inline.

config is optional. When not specified, the default configuration of the resolved bundle will be used.

| | | +| `config` _[ClusterExtensionConfig](#clusterextensionconfig)_ | config contains optional configuration values applied during rendering of the
ClusterExtension's manifests. Values can be specified inline.

config is optional. When not specified, the default configuration of the resolved bundle will be used. | | | #### ClusterExtensionStatus diff --git a/docs/draft/howto/single-ownnamespace-install.md b/docs/draft/howto/single-ownnamespace-install.md index fc36de0e75..41ecdb6cc2 100644 --- a/docs/draft/howto/single-ownnamespace-install.md +++ b/docs/draft/howto/single-ownnamespace-install.md @@ -1,8 +1,7 @@ ## Description !!! note -This feature is still in *alpha* the `SingleOwnNamespaceInstallSupport` feature-gate must be enabled to make use of it. -See the instructions below on how to enable it. +The `SingleOwnNamespaceInstallSupport` feature-gate is enabled by default. Use this guide to configure bundles that need Single or Own namespace install modes. --- @@ -31,28 +30,6 @@ include *installModes*. [![OwnNamespace Install Demo](https://asciinema.org/a/Rxx6WUwAU016bXFDW74XLcM5i.svg)](https://asciinema.org/a/Rxx6WUwAU016bXFDW74XLcM5i) -## Enabling the Feature-Gate - -!!! tip - -This guide assumes OLMv1 is already installed. If that is not the case, -you can follow the [getting started](../../getting-started/olmv1_getting_started.md) guide to install OLMv1. - ---- - -Patch the `operator-controller` `Deployment` adding `--feature-gates=SingleOwnNamespaceInstallSupport=true` to the -controller container arguments: - -```terminal title="Enable SingleOwnNamespaceInstallSupport feature-gate" -kubectl patch deployment -n olmv1-system operator-controller-controller-manager --type='json' -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--feature-gates=SingleOwnNamespaceInstallSupport=true"}]' -``` - -Wait for `Deployment` rollout: - -```terminal title="Wait for Deployment rollout" -kubectl rollout status -n olmv1-system deployment/operator-controller-controller-manager -``` - ## Configuring the `ClusterExtension` A `ClusterExtension` can be configured to install bundle in `Single-` or `OwnNamespace` mode through the diff --git a/docs/draft/tutorials/explore-available-content-metas-endpoint.md b/docs/draft/tutorials/explore-available-content-metas-endpoint.md index 70cb87424e..c75009423d 100644 --- a/docs/draft/tutorials/explore-available-content-metas-endpoint.md +++ b/docs/draft/tutorials/explore-available-content-metas-endpoint.md @@ -91,8 +91,9 @@ Then you can query the catalog by using `curl` commands and the `jq` CLI tool to ... ``` + !!! important - Currently, OLM 1.0 does not support the installation of extensions that use webhooks or that target a single or specified set of namespaces. + Currently, OLM 1.0 does not support the installation of extensions that use webhooks. 3. Return list of packages which support `AllNamespaces` install mode, do not use webhooks, and where the channel head version uses `olm.csv.metadata` format: diff --git a/docs/project/olmv1_limitations.md b/docs/project/olmv1_limitations.md index 26e2340ff5..54e174b4ca 100644 --- a/docs/project/olmv1_limitations.md +++ b/docs/project/olmv1_limitations.md @@ -8,8 +8,7 @@ hide: Currently, OLM v1 only supports installing operators packaged in [OLM v0 bundles](https://olm.operatorframework.io/docs/tasks/creating-operator-bundle/) , also known as `registry+v1` bundles. Additionally, the bundled operator, or cluster extension: -* **must** support installation via the `AllNamespaces` install mode. -* **must not** use webhooks. +* **must** support installation via the `AllNamespaces`, `SingleNamespace`, or `OwnNamespace` install modes. * **must not** declare dependencies using any of the following file-based catalog properties: * `olm.gvk.required` * `olm.package.required` diff --git a/docs/tutorials/explore-available-content.md b/docs/tutorials/explore-available-content.md index 0a1f468093..1533ac49ef 100644 --- a/docs/tutorials/explore-available-content.md +++ b/docs/tutorials/explore-available-content.md @@ -91,8 +91,9 @@ Then you can query the catalog by using `curl` commands and the `jq` CLI tool to ... ``` + !!! important - Currently, OLM 1.0 does not support the installation of extensions that use webhooks or that target a single or specified set of namespaces. + Currently, OLM 1.0 does not support the installation of extensions that use webhooks. 3. Return list of packages that support `AllNamespaces` install mode and do not use webhooks: diff --git a/hack/demo/own-namespace-demo-script.sh b/hack/demo/own-namespace-demo-script.sh index 611c6dfb05..159957bfb2 100755 --- a/hack/demo/own-namespace-demo-script.sh +++ b/hack/demo/own-namespace-demo-script.sh @@ -6,16 +6,14 @@ set -e trap 'echo "Demo ran into error"; trap - SIGTERM && kill -- -$$; exit 1' ERR SIGINT SIGTERM EXIT -# install experimental CRDs with config field support -kubectl apply -f "$(dirname "${BASH_SOURCE[0]}")/../../manifests/experimental.yaml" +# install standard CRDs +echo "Install standard CRDs..." +kubectl apply -f "$(dirname "${BASH_SOURCE[0]}")/../../manifests/base.yaml" -# wait for experimental CRDs to be available +# wait for standard CRDs to be available kubectl wait --for condition=established --timeout=60s crd/clusterextensions.olm.operatorframework.io -# enable 'SingleOwnNamespaceInstallSupport' feature gate -kubectl patch deployment -n olmv1-system operator-controller-controller-manager --type='json' -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--feature-gates=SingleOwnNamespaceInstallSupport=true"}]' - -# wait for operator-controller to become available +# Ensure controller is healthy kubectl rollout status -n olmv1-system deployment/operator-controller-controller-manager # create install namespace @@ -57,17 +55,6 @@ kubectl delete clusterextension argocd-operator --ignore-not-found=true kubectl delete namespace argocd-system --ignore-not-found=true kubectl delete clusterrolebinding argocd-installer-crb --ignore-not-found=true -# remove feature gate from deployment -echo "Removing feature gate from operator-controller..." -kubectl patch deployment -n olmv1-system operator-controller-controller-manager --type='json' -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/args", "value": "--feature-gates=SingleOwnNamespaceInstallSupport=true"}]' || true - -# restore standard CRDs -echo "Restoring standard CRDs..." -kubectl apply -f "$(dirname "${BASH_SOURCE[0]}")/../../manifests/base.yaml" - -# wait for standard CRDs to be available -kubectl wait --for condition=established --timeout=60s crd/clusterextensions.olm.operatorframework.io - # wait for operator-controller to become available with standard config kubectl rollout status -n olmv1-system deployment/operator-controller-controller-manager diff --git a/hack/demo/single-namespace-demo-script.sh b/hack/demo/single-namespace-demo-script.sh index 9702684152..8fb2667abb 100755 --- a/hack/demo/single-namespace-demo-script.sh +++ b/hack/demo/single-namespace-demo-script.sh @@ -6,16 +6,14 @@ set -e trap 'echo "Demo ran into error"; trap - SIGTERM && kill -- -$$; exit 1' ERR SIGINT SIGTERM EXIT -# install experimental CRDs with config field support -kubectl apply -f "$(dirname "${BASH_SOURCE[0]}")/../../manifests/experimental.yaml" +# install standard CRDs +echo "Install standard CRDs..." +kubectl apply -f "$(dirname "${BASH_SOURCE[0]}")/../../manifests/base.yaml" -# wait for experimental CRDs to be available +# wait for standard CRDs to be available kubectl wait --for condition=established --timeout=60s crd/clusterextensions.olm.operatorframework.io -# enable 'SingleOwnNamespaceInstallSupport' feature gate -kubectl patch deployment -n olmv1-system operator-controller-controller-manager --type='json' -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--feature-gates=SingleOwnNamespaceInstallSupport=true"}]' - -# wait for operator-controller to become available +# Ensure controller is healthy kubectl rollout status -n olmv1-system deployment/operator-controller-controller-manager # create install namespace @@ -60,17 +58,6 @@ kubectl delete clusterextension argocd-operator --ignore-not-found=true kubectl delete namespace argocd-system argocd --ignore-not-found=true kubectl delete clusterrolebinding argocd-installer-crb --ignore-not-found=true -# remove feature gate from deployment -echo "Removing feature gate from operator-controller..." -kubectl patch deployment -n olmv1-system operator-controller-controller-manager --type='json' -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/args", "value": "--feature-gates=SingleOwnNamespaceInstallSupport=true"}]' || true - -# restore standard CRDs -echo "Restoring standard CRDs..." -kubectl apply -f "$(dirname "${BASH_SOURCE[0]}")/../../manifests/base.yaml" - -# wait for standard CRDs to be available -kubectl wait --for condition=established --timeout=60s crd/clusterextensions.olm.operatorframework.io - # wait for operator-controller to become available with standard config kubectl rollout status -n olmv1-system deployment/operator-controller-controller-manager diff --git a/helm/experimental.yaml b/helm/experimental.yaml index ae98c08031..3a07ac271a 100644 --- a/helm/experimental.yaml +++ b/helm/experimental.yaml @@ -10,7 +10,6 @@ options: features: enabled: - WebhookProviderCertManager - - SingleOwnNamespaceInstallSupport - PreflightPermissions - HelmChartSupport - BoxcutterRuntime diff --git a/helm/olmv1/base/operator-controller/crd/standard/olm.operatorframework.io_clusterextensions.yaml b/helm/olmv1/base/operator-controller/crd/standard/olm.operatorframework.io_clusterextensions.yaml index a0983e41f9..aa33f263b1 100644 --- a/helm/olmv1/base/operator-controller/crd/standard/olm.operatorframework.io_clusterextensions.yaml +++ b/helm/olmv1/base/operator-controller/crd/standard/olm.operatorframework.io_clusterextensions.yaml @@ -57,6 +57,40 @@ spec: description: spec is an optional field that defines the desired state of the ClusterExtension. properties: + config: + description: |- + config contains optional configuration values applied during rendering of the + ClusterExtension's manifests. Values can be specified inline. + + config is optional. When not specified, the default configuration of the resolved bundle will be used. + properties: + configType: + description: |- + configType is a required reference to the type of configuration source. + + Allowed values are "Inline" + + When this field is set to "Inline", the cluster extension configuration is defined inline within the + ClusterExtension resource. + enum: + - Inline + type: string + inline: + description: |- + inline contains JSON or YAML values specified directly in the + ClusterExtension. + + inline must be set if configType is 'Inline'. + type: object + x-kubernetes-preserve-unknown-fields: true + required: + - configType + type: object + x-kubernetes-validations: + - message: inline is required when configType is Inline, and forbidden + otherwise + rule: 'has(self.configType) && self.configType == ''Inline'' ?has(self.inline) + : !has(self.inline)' install: description: |- install is an optional field used to configure the installation options diff --git a/helm/tilt.yaml b/helm/tilt.yaml index 3dbc373c7e..903c089749 100644 --- a/helm/tilt.yaml +++ b/helm/tilt.yaml @@ -15,7 +15,6 @@ options: features: enabled: - WebhookProviderCertManager - - SingleOwnNamespaceInstallSupport - PreflightPermissions - HelmChartSupport disabled: diff --git a/internal/operator-controller/features/features.go b/internal/operator-controller/features/features.go index 1abdf0a18a..3297e4f1b6 100644 --- a/internal/operator-controller/features/features.go +++ b/internal/operator-controller/features/features.go @@ -33,8 +33,8 @@ var operatorControllerFeatureGates = map[featuregate.Feature]featuregate.Feature // registry+v1 cluster extensions with single or own namespaces modes // i.e. with a single watch namespace. SingleOwnNamespaceInstallSupport: { - Default: false, - PreRelease: featuregate.Alpha, + Default: true, + PreRelease: featuregate.GA, LockToDefault: false, }, diff --git a/manifests/experimental-e2e.yaml b/manifests/experimental-e2e.yaml index 39ff01d611..c5143f53a7 100644 --- a/manifests/experimental-e2e.yaml +++ b/manifests/experimental-e2e.yaml @@ -2184,7 +2184,6 @@ spec: - --metrics-bind-address=:8443 - --leader-elect - --feature-gates=WebhookProviderCertManager=true - - --feature-gates=SingleOwnNamespaceInstallSupport=true - --feature-gates=PreflightPermissions=true - --feature-gates=HelmChartSupport=true - --feature-gates=BoxcutterRuntime=true diff --git a/manifests/experimental.yaml b/manifests/experimental.yaml index 86bba145d4..212eb28e58 100644 --- a/manifests/experimental.yaml +++ b/manifests/experimental.yaml @@ -2097,7 +2097,6 @@ spec: - --metrics-bind-address=:8443 - --leader-elect - --feature-gates=WebhookProviderCertManager=true - - --feature-gates=SingleOwnNamespaceInstallSupport=true - --feature-gates=PreflightPermissions=true - --feature-gates=HelmChartSupport=true - --feature-gates=BoxcutterRuntime=true diff --git a/manifests/standard-e2e.yaml b/manifests/standard-e2e.yaml index 783beec515..0a3a070327 100644 --- a/manifests/standard-e2e.yaml +++ b/manifests/standard-e2e.yaml @@ -648,6 +648,40 @@ spec: description: spec is an optional field that defines the desired state of the ClusterExtension. properties: + config: + description: |- + config contains optional configuration values applied during rendering of the + ClusterExtension's manifests. Values can be specified inline. + + config is optional. When not specified, the default configuration of the resolved bundle will be used. + properties: + configType: + description: |- + configType is a required reference to the type of configuration source. + + Allowed values are "Inline" + + When this field is set to "Inline", the cluster extension configuration is defined inline within the + ClusterExtension resource. + enum: + - Inline + type: string + inline: + description: |- + inline contains JSON or YAML values specified directly in the + ClusterExtension. + + inline must be set if configType is 'Inline'. + type: object + x-kubernetes-preserve-unknown-fields: true + required: + - configType + type: object + x-kubernetes-validations: + - message: inline is required when configType is Inline, and forbidden + otherwise + rule: 'has(self.configType) && self.configType == ''Inline'' ?has(self.inline) + : !has(self.inline)' install: description: |- install is an optional field used to configure the installation options diff --git a/manifests/standard.yaml b/manifests/standard.yaml index 95e400c264..fc7b54f151 100644 --- a/manifests/standard.yaml +++ b/manifests/standard.yaml @@ -613,6 +613,40 @@ spec: description: spec is an optional field that defines the desired state of the ClusterExtension. properties: + config: + description: |- + config contains optional configuration values applied during rendering of the + ClusterExtension's manifests. Values can be specified inline. + + config is optional. When not specified, the default configuration of the resolved bundle will be used. + properties: + configType: + description: |- + configType is a required reference to the type of configuration source. + + Allowed values are "Inline" + + When this field is set to "Inline", the cluster extension configuration is defined inline within the + ClusterExtension resource. + enum: + - Inline + type: string + inline: + description: |- + inline contains JSON or YAML values specified directly in the + ClusterExtension. + + inline must be set if configType is 'Inline'. + type: object + x-kubernetes-preserve-unknown-fields: true + required: + - configType + type: object + x-kubernetes-validations: + - message: inline is required when configType is Inline, and forbidden + otherwise + rule: 'has(self.configType) && self.configType == ''Inline'' ?has(self.inline) + : !has(self.inline)' install: description: |- install is an optional field used to configure the installation options diff --git a/test/e2e/single_namespace_support_test.go b/test/e2e/single_namespace_support_test.go new file mode 100644 index 0000000000..d8e9b6c92c --- /dev/null +++ b/test/e2e/single_namespace_support_test.go @@ -0,0 +1,163 @@ +package e2e + +import ( + "context" + "fmt" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + apimeta "k8s.io/apimachinery/pkg/api/meta" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/ptr" + + ocv1 "github.com/operator-framework/operator-controller/api/v1" + utils "github.com/operator-framework/operator-controller/internal/shared/util/testutils" +) + +func TestClusterExtensionConfigSupport(t *testing.T) { + t.Log("Test support for cluster extension config") + defer utils.CollectTestArtifacts(t, artifactName, c, cfg) + + t.Log("By creating install namespace, watch namespace and necessary rbac resources") + namespace := corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-operator", + }, + } + require.NoError(t, c.Create(t.Context(), &namespace)) + t.Cleanup(func() { + require.NoError(t, c.Delete(context.Background(), &namespace)) + }) + + watchNamespace := corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-operator-watch", + }, + } + require.NoError(t, c.Create(t.Context(), &watchNamespace)) + t.Cleanup(func() { + require.NoError(t, c.Delete(context.Background(), &watchNamespace)) + }) + + serviceAccount := corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-operator-installer", + Namespace: namespace.GetName(), + }, + } + require.NoError(t, c.Create(t.Context(), &serviceAccount)) + t.Cleanup(func() { + require.NoError(t, c.Delete(context.Background(), &serviceAccount)) + }) + + clusterRoleBinding := &rbacv1.ClusterRoleBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-operator-installer", + }, + Subjects: []rbacv1.Subject{ + { + Kind: "ServiceAccount", + APIGroup: corev1.GroupName, + Name: serviceAccount.GetName(), + Namespace: serviceAccount.GetNamespace(), + }, + }, + RoleRef: rbacv1.RoleRef{ + APIGroup: rbacv1.GroupName, + Kind: "ClusterRole", + Name: "cluster-admin", + }, + } + require.NoError(t, c.Create(t.Context(), clusterRoleBinding)) + t.Cleanup(func() { + require.NoError(t, c.Delete(context.Background(), clusterRoleBinding)) + }) + + t.Log("By creating the test-operator ClusterCatalog") + extensionCatalog := &ocv1.ClusterCatalog{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-operator-catalog", + }, + Spec: ocv1.ClusterCatalogSpec{ + Source: ocv1.CatalogSource{ + Type: ocv1.SourceTypeImage, + Image: &ocv1.ImageSource{ + Ref: fmt.Sprintf("%s/e2e/test-catalog:v1", os.Getenv("CLUSTER_REGISTRY_HOST")), + PollIntervalMinutes: ptr.To(1), + }, + }, + }, + } + require.NoError(t, c.Create(t.Context(), extensionCatalog)) + t.Cleanup(func() { + require.NoError(t, c.Delete(context.Background(), extensionCatalog)) + }) + + t.Log("By waiting for the catalog to serve its metadata") + require.EventuallyWithT(t, func(ct *assert.CollectT) { + require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: extensionCatalog.GetName()}, extensionCatalog)) + cond := apimeta.FindStatusCondition(extensionCatalog.Status.Conditions, ocv1.TypeServing) + require.NotNil(ct, cond) + require.Equal(ct, metav1.ConditionTrue, cond.Status) + require.Equal(ct, ocv1.ReasonAvailable, cond.Reason) + }, pollDuration, pollInterval) + + t.Log("By installing the test-operator ClusterExtension configured in SingleNamespace mode") + clusterExtension := &ocv1.ClusterExtension{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-operator-extension", + }, + Spec: ocv1.ClusterExtensionSpec{ + Source: ocv1.SourceConfig{ + SourceType: "Catalog", + Catalog: &ocv1.CatalogFilter{ + PackageName: "test", + Selector: &metav1.LabelSelector{ + MatchLabels: map[string]string{"olm.operatorframework.io/metadata.name": extensionCatalog.Name}, + }, + }, + }, + Namespace: namespace.GetName(), + ServiceAccount: ocv1.ServiceAccountReference{ + Name: serviceAccount.GetName(), + }, + Config: &ocv1.ClusterExtensionConfig{ + ConfigType: ocv1.ClusterExtensionConfigTypeInline, + Inline: &apiextensionsv1.JSON{ + Raw: []byte(fmt.Sprintf(`{"watchNamespace": "%s"}`, watchNamespace.GetName())), + }, + }, + }, + } + require.NoError(t, c.Create(t.Context(), clusterExtension)) + t.Cleanup(func() { + require.NoError(t, c.Delete(context.Background(), clusterExtension)) + }) + + t.Log("By waiting for test-operator extension to be installed successfully") + require.EventuallyWithT(t, func(ct *assert.CollectT) { + require.NoError(ct, c.Get(t.Context(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension)) + cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1.TypeInstalled) + require.NotNil(ct, cond) + require.Equal(ct, metav1.ConditionTrue, cond.Status) + require.Equal(ct, ocv1.ReasonSucceeded, cond.Reason) + require.Contains(ct, cond.Message, "Installed bundle") + require.NotNil(ct, clusterExtension.Status.Install) + require.NotEmpty(ct, clusterExtension.Status.Install.Bundle) + }, pollDuration, pollInterval) + + t.Log("By ensuring the test-operator deployment is correctly configured to watch the watch namespace") + require.EventuallyWithT(t, func(ct *assert.CollectT) { + deployment := &appsv1.Deployment{} + require.NoError(ct, c.Get(t.Context(), types.NamespacedName{Namespace: namespace.GetName(), Name: "test-operator"}, deployment)) + require.NotNil(ct, deployment.Spec.Template.GetAnnotations()) + require.Equal(ct, watchNamespace.GetName(), deployment.Spec.Template.GetAnnotations()["olm.targetNamespaces"]) + }, pollDuration, pollInterval) +} diff --git a/test/experimental-e2e/experimental_e2e_test.go b/test/experimental-e2e/experimental_e2e_test.go index fca2511f76..fa22c0c956 100644 --- a/test/experimental-e2e/experimental_e2e_test.go +++ b/test/experimental-e2e/experimental_e2e_test.go @@ -249,147 +249,6 @@ func TestWebhookSupport(t *testing.T) { }, res.Object["spec"]) } -func TestClusterExtensionConfigSupport(t *testing.T) { - t.Log("Test support for cluster extension config") - defer utils.CollectTestArtifacts(t, artifactName, c, cfg) - - t.Log("By creating install namespace, watch namespace and necessary rbac resources") - namespace := corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-operator", - }, - } - require.NoError(t, c.Create(t.Context(), &namespace)) - t.Cleanup(func() { - require.NoError(t, c.Delete(context.Background(), &namespace)) - }) - - watchNamespace := corev1.Namespace{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-operator-watch", - }, - } - require.NoError(t, c.Create(t.Context(), &watchNamespace)) - t.Cleanup(func() { - require.NoError(t, c.Delete(context.Background(), &watchNamespace)) - }) - - serviceAccount := corev1.ServiceAccount{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-operator-installer", - Namespace: namespace.GetName(), - }, - } - require.NoError(t, c.Create(t.Context(), &serviceAccount)) - t.Cleanup(func() { - require.NoError(t, c.Delete(context.Background(), &serviceAccount)) - }) - - clusterRoleBinding := &rbacv1.ClusterRoleBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-operator-installer", - }, - Subjects: []rbacv1.Subject{ - { - Kind: "ServiceAccount", - APIGroup: corev1.GroupName, - Name: serviceAccount.GetName(), - Namespace: serviceAccount.GetNamespace(), - }, - }, - RoleRef: rbacv1.RoleRef{ - APIGroup: rbacv1.GroupName, - Kind: "ClusterRole", - Name: "cluster-admin", - }, - } - require.NoError(t, c.Create(t.Context(), clusterRoleBinding)) - t.Cleanup(func() { - require.NoError(t, c.Delete(context.Background(), clusterRoleBinding)) - }) - - t.Log("By creating the test-operator ClusterCatalog") - extensionCatalog := &ocv1.ClusterCatalog{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-operator-catalog", - }, - Spec: ocv1.ClusterCatalogSpec{ - Source: ocv1.CatalogSource{ - Type: ocv1.SourceTypeImage, - Image: &ocv1.ImageSource{ - Ref: fmt.Sprintf("%s/e2e/test-catalog:v1", os.Getenv("CLUSTER_REGISTRY_HOST")), - PollIntervalMinutes: ptr.To(1), - }, - }, - }, - } - require.NoError(t, c.Create(t.Context(), extensionCatalog)) - t.Cleanup(func() { - require.NoError(t, c.Delete(context.Background(), extensionCatalog)) - }) - - t.Log("By waiting for the catalog to serve its metadata") - require.EventuallyWithT(t, func(ct *assert.CollectT) { - require.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: extensionCatalog.GetName()}, extensionCatalog)) - cond := apimeta.FindStatusCondition(extensionCatalog.Status.Conditions, ocv1.TypeServing) - require.NotNil(ct, cond) - require.Equal(ct, metav1.ConditionTrue, cond.Status) - require.Equal(ct, ocv1.ReasonAvailable, cond.Reason) - }, pollDuration, pollInterval) - - t.Log("By installing the test-operator ClusterExtension configured in SingleNamespace mode") - clusterExtension := &ocv1.ClusterExtension{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-operator-extension", - }, - Spec: ocv1.ClusterExtensionSpec{ - Source: ocv1.SourceConfig{ - SourceType: "Catalog", - Catalog: &ocv1.CatalogFilter{ - PackageName: "test", - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{"olm.operatorframework.io/metadata.name": extensionCatalog.Name}, - }, - }, - }, - Namespace: namespace.GetName(), - ServiceAccount: ocv1.ServiceAccountReference{ - Name: serviceAccount.GetName(), - }, - Config: &ocv1.ClusterExtensionConfig{ - ConfigType: ocv1.ClusterExtensionConfigTypeInline, - Inline: &apiextensionsv1.JSON{ - Raw: []byte(fmt.Sprintf(`{"watchNamespace": "%s"}`, watchNamespace.GetName())), - }, - }, - }, - } - require.NoError(t, c.Create(t.Context(), clusterExtension)) - t.Cleanup(func() { - require.NoError(t, c.Delete(context.Background(), clusterExtension)) - }) - - t.Log("By waiting for test-operator extension to be installed successfully") - require.EventuallyWithT(t, func(ct *assert.CollectT) { - require.NoError(ct, c.Get(t.Context(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension)) - cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1.TypeInstalled) - require.NotNil(ct, cond) - require.Equal(ct, metav1.ConditionTrue, cond.Status) - require.Equal(ct, ocv1.ReasonSucceeded, cond.Reason) - require.Contains(ct, cond.Message, "Installed bundle") - require.NotNil(ct, clusterExtension.Status.Install) - require.NotEmpty(ct, clusterExtension.Status.Install.Bundle) - }, pollDuration, pollInterval) - - t.Log("By ensuring the test-operator deployment is correctly configured to watch the watch namespace") - require.EventuallyWithT(t, func(ct *assert.CollectT) { - deployment := &appsv1.Deployment{} - require.NoError(ct, c.Get(t.Context(), types.NamespacedName{Namespace: namespace.GetName(), Name: "test-operator"}, deployment)) - require.NotNil(ct, deployment.Spec.Template.GetAnnotations()) - require.Equal(ct, watchNamespace.GetName(), deployment.Spec.Template.GetAnnotations()["olm.targetNamespaces"]) - }, pollDuration, pollInterval) -} - func TestClusterExtensionVersionUpdate(t *testing.T) { t.Log("When a cluster extension is installed from a catalog") t.Log("When resolving upgrade edges")