From 7a045e1fc066d0291c393cefa94f870b52a01f4b Mon Sep 17 00:00:00 2001 From: Joe Lanford Date: Thu, 2 May 2024 17:28:20 -0400 Subject: [PATCH] remove olm.bundle.mediatype property and clusterextension support for plain+v0 Signed-off-by: Joe Lanford --- Makefile | 3 - docs/demos/coast-to-coast-q4-2023.md | 950 ------------------ internal/catalogmetadata/types.go | 28 - internal/catalogmetadata/types_test.go | 56 -- .../clusterextension_controller.go | 34 +- .../clusterextension_controller_test.go | 150 --- internal/controllers/extension_controller.go | 26 +- test/e2e/cluster_extension_install_test.go | 57 -- .../extension_developer_test.go | 9 - test/extension-developer-e2e/setup.sh | 87 +- .../bundles/plain-v0/plain.v0.1.0/Dockerfile | 2 - .../plain.v0.1.0/manifests/configmap.yaml | 19 - testdata/catalogs/test-catalog/catalog.yaml | 24 +- 13 files changed, 11 insertions(+), 1434 deletions(-) delete mode 100644 docs/demos/coast-to-coast-q4-2023.md delete mode 100644 testdata/bundles/plain-v0/plain.v0.1.0/Dockerfile delete mode 100644 testdata/bundles/plain-v0/plain.v0.1.0/manifests/configmap.yaml diff --git a/Makefile b/Makefile index 1ec07a352..01c9eb897 100644 --- a/Makefile +++ b/Makefile @@ -123,7 +123,6 @@ e2e: #EXHELP Run the e2e tests. E2E_REGISTRY_NAME := docker-registry E2E_REGISTRY_NAMESPACE := operator-controller-e2e export REG_PKG_NAME := registry-operator -export PLAIN_PKG_NAME := plain-operator export CATALOG_IMG := $(E2E_REGISTRY_NAME).$(E2E_REGISTRY_NAMESPACE).svc:5000/test-catalog:e2e .PHONY: test-ext-dev-e2e test-ext-dev-e2e: $(OPERATOR_SDK) $(KUSTOMIZE) $(KIND) #HELP Run extension create, upgrade and delete tests. @@ -187,12 +186,10 @@ kind-load-test-artifacts: $(KIND) #EXHELP Load the e2e testdata container images $(CONTAINER_RUNTIME) tag localhost/testdata/bundles/registry-v1/prometheus-operator:v1.0.0 localhost/testdata/bundles/registry-v1/prometheus-operator:v1.0.1 $(CONTAINER_RUNTIME) tag localhost/testdata/bundles/registry-v1/prometheus-operator:v1.0.0 localhost/testdata/bundles/registry-v1/prometheus-operator:v1.2.0 $(CONTAINER_RUNTIME) tag localhost/testdata/bundles/registry-v1/prometheus-operator:v1.0.0 localhost/testdata/bundles/registry-v1/prometheus-operator:v2.0.0 - $(CONTAINER_RUNTIME) build testdata/bundles/plain-v0/plain.v0.1.0 -t localhost/testdata/bundles/plain-v0/plain:v0.1.0 $(KIND) load docker-image localhost/testdata/bundles/registry-v1/prometheus-operator:v1.0.0 --name $(KIND_CLUSTER_NAME) $(KIND) load docker-image localhost/testdata/bundles/registry-v1/prometheus-operator:v1.0.1 --name $(KIND_CLUSTER_NAME) $(KIND) load docker-image localhost/testdata/bundles/registry-v1/prometheus-operator:v1.2.0 --name $(KIND_CLUSTER_NAME) $(KIND) load docker-image localhost/testdata/bundles/registry-v1/prometheus-operator:v2.0.0 --name $(KIND_CLUSTER_NAME) - $(KIND) load docker-image localhost/testdata/bundles/plain-v0/plain:v0.1.0 --name $(KIND_CLUSTER_NAME) #SECTION Build diff --git a/docs/demos/coast-to-coast-q4-2023.md b/docs/demos/coast-to-coast-q4-2023.md deleted file mode 100644 index c8a879885..000000000 --- a/docs/demos/coast-to-coast-q4-2023.md +++ /dev/null @@ -1,950 +0,0 @@ -# Coast-to-coast Demo for Q4 2023 - -This coast-to-coast demo highlights some of the new features introduced to OLMv1 in Q4 of 2023. - -New Features: -- `Catalog` polling -- Version range support on the `spec.version` field for `ClusterExtension` resources -- Semver upgrade constraint policy -- `BundleDeployment` health status - -This document will go through an example that highlights each of these new features. Each step will be documented as if you are following along and will be done sequentially. This document will also use some values specific to this example and in your own projects should be replaced to use a different value. - -## Prerequisites -- A running Kubernetes cluster where you have admin privileges -- `operator-sdk` installed - - Installation instructions can be found at https://sdk.operatorframework.io/docs/installation/ -- `kubectl` installed - - Installation instructions can be found at https://kubernetes.io/docs/tasks/tools/ -- A container runtime of your choice, in this demo we will be using `docker` -- Install `operator-controller` v0.8.0 - - Installation instructions can be found at https://github.com/operator-framework/operator-controller/releases/tag/v0.8.0 -- `kustomize` installed - - Installation instructions can be found at https://kubectl.docs.kubernetes.io/installation/kustomize/ -- `yq` installed - - Installation instructions can be found at https://github.com/mikefarah/yq/#install -## Prepare for takeoff - -Before we can start exploring the new features we need to do some preparation by creating a new -extension and building a few different versions. - -### Create an extension ->[!NOTE] ->In this demo, we aren't going to make the extension do anything. - -We will create a new extension using the `operator-sdk`. - -- Create a new directory for the project and `cd` into it: -```sh -mkdir coastal && cd coastal -``` - -- Initialize the project: -```sh -operator-sdk init --domain coastal.operatorframework.io -``` - -- Create a new API: -```sh -operator-sdk create api \ - --group coastal.operatorframework.io \ - --version v1alpha1 \ - --kind Coast \ - --resource --controller -``` - -### Build the extension and bundle images -For this demo we are going to build a several different versions of this extension: -- `v1.0.0-alpha1` -- `v1.0.0` -- `v1.0.1` -- `v1.1.0` -- `v2.0.0` - -Initial setup: -- Create the `manifests/` directory for building the plain bundle -```sh - mkdir -p manifests -``` - -- Create a Dockerfile for the plain bundle image -```sh -cat << EOF > plainbundle.Dockerfile -FROM scratch -ADD manifests /manifests -EOF -``` - -For each of the versions above, perform the following actions: -- Generate the manifests -```sh - make generate manifests -``` - -- Build the controller image -```sh - make docker-build IMG="quay.io/operator-framework/coastal:{VERSION}" -``` - -- Populate the `manifests/` directory for building the plain bundle -```sh - kustomize build config/default > manifests/manifests.yaml -``` - -- Build the plain bundle image -```sh -docker build -t quay.io/operator-framework/coastal-bundle:{VERSION} -f plainbundle.Dockerfile . -``` - -- Push the controller image and plain bundle image -```sh -docker push quay.io/operator-framework/coastal:{VERSION} && \ -docker push quay.io/operator-framework/coastal-bundle:{VERSION} -``` - -A handy little script to run all these steps for you: -```sh -#!/usr/bin/env bash -set -e - -mkdir -p manifests - -cat << EOF > plainbundle.Dockerfile -FROM scratch -ADD manifests /manifests -EOF - -versions=( v1.0.0-alpha1 v1.0.0 v1.0.1 v1.1.0 v2.0.0 ) -for version in "${versions[@]}" -do - make generate manifests - make docker-build IMG="quay.io/operator-framework/coastal:${version}" - mkdir -p manifests - kustomize build config/default > manifests/manifests.yaml - docker build -t "quay.io/operator-framework/coastal-bundle:${version}" -f plainbundle.Dockerfile . - docker push "quay.io/operator-framework/coastal:${version}" - docker push "quay.io/operator-framework/coastal-bundle:${version}" -done -``` - -### Create an initial File-Based Catalog (FBC) Image -Now we need to build and push an initial File-Based Catalog (FBC) image containing -our bundles. To help highlight the new polling functionality, we will generate a catalog containing -only the `v1.0.0-alpha1` bundle and we will mimic active development by incrementally updating the catalog -image to include more of our bundles. - -- Create a `catalog/` directory -```sh -mkdir catalog -``` - -- Create a Dockerfile for the catalog image -```sh -cat << EOF > catalog.Dockerfile -FROM scratch -ADD catalog /configs -LABEL operators.operatorframework.io.index.configs.v1=/configs -EOF -``` - -- Create the FBC YAML file -```sh -cat << EOF > catalog/index.yaml -schema: olm.package -name: coastal ---- -schema: olm.bundle -name: coastal.v1.0.0-alpha1 -package: coastal -image: quay.io/operator-framework/coastal-bundle:v1.0.0-alpha1 -properties: - - type: olm.package - value: - packageName: coastal - version: 1.0.0-alpha1 - - type: olm.bundle.mediatype - value: plain+v0 ---- -schema: olm.channel -name: stable -package: coastal -entries: - - name: coastal.v1.0.0-alpha1 -EOF -``` - -- Build and push the catalog image -```sh -docker build -t quay.io/operator-framework/coastal-catalog:latest -f catalog.Dockerfile . && \ -docker push quay.io/operator-framework/coastal-catalog:latest -``` - -### Create a `Catalog` Resource -Create a `Catalog` resource that references the catalog image we built -in the previous step and specify a polling interval of 15 seconds. This will make sure that the updates -we make to the catalog image are reflected on our cluster relatively quickly. - -- Create the `Catalog` resource: -```sh -kubectl apply -f - < -Example - -```yaml -apiVersion: olm.operatorframework.io/v1alpha1 -kind: ClusterExtension -metadata: - annotations: - kubectl.kubernetes.io/last-applied-configuration: | - {"apiVersion":"olm.operatorframework.io/v1alpha1","kind":"ClusterExtension","metadata":{"annotations":{},"name":"coastal"},"spec":{"packageName":"coastal","version":"1.0.x"}} - creationTimestamp: "2023-11-27T20:29:18Z" - generation: 1 - name: coastal - resourceVersion: "2983" - uid: 48d16240-edae-4904-bad8-58137bebcf8a -spec: - packageName: coastal - upgradeConstraintPolicy: Enforce - version: 1.0.x -status: - conditions: - - lastTransitionTime: "2023-11-27T20:29:18Z" - message: installation has not been attempted as resolution failed - observedGeneration: 1 - reason: InstallationStatusUnknown - status: Unknown - type: Installed - - lastTransitionTime: "2023-11-27T20:29:18Z" - message: no package "coastal" matching version "1.0.x" found - observedGeneration: 1 - reason: ResolutionFailed - status: "False" - type: Resolved -``` - - - ->[!NOTE] ->The above command establishes a watch on the `ClusterExtension` resource and blocks. Once you are done verifying ->the resolution status you can exit the command with `ctrl+c` - -### Update the FBC Image to contain a bundle for `v1.0.0` -To highlight both the polling functionality and the version range constraints, let's add the `v1.0.0` bundle -of our extension to the catalog image we created in the preparation steps and push the changes. - -- Add the new bundle to the catalog YAML file -```sh -cat << EOF >> catalog/index.yaml ---- -schema: olm.bundle -name: coastal.v1.0.0 -package: coastal -image: quay.io/operator-framework/coastal-bundle:v1.0.0 -properties: - - type: olm.package - value: - packageName: coastal - version: 1.0.0 - - type: olm.bundle.mediatype - value: plain+v0 -EOF -``` - -- Using `yq`, update the channel to include this bundle as an entry -```sh -yq eval 'select(.schema=="olm.channel" and .name == "stable").entries += [{"name" : "coastal.v1.0.0"}]' -i catalog/index.yaml -``` - -- Build and push the catalog image -```sh -docker build -t quay.io/operator-framework/coastal-catalog:latest -f catalog.Dockerfile . && \ -docker push quay.io/operator-framework/coastal-catalog:latest -``` - -Shortly, we should see that the `Catalog` resource updates to have a new resolved reference and the `ClusterExtension` resource we created previously is successfully installed. - -Verify this for the `ClusterExtension` with: -```sh -kubectl get clusterextension/coastal -o yaml -w -``` - -
-Example - -```yaml -apiVersion: olm.operatorframework.io/v1alpha1 -kind: ClusterExtension -metadata: - annotations: - kubectl.kubernetes.io/last-applied-configuration: | - {"apiVersion":"olm.operatorframework.io/v1alpha1","kind":"ClusterExtension","metadata":{"annotations":{},"name":"coastal"},"spec":{"packageName":"coastal","version":"1.0.x"}} - creationTimestamp: "2023-11-27T20:29:18Z" - generation: 1 - name: coastal - resourceVersion: "3875" - uid: 48d16240-edae-4904-bad8-58137bebcf8a -spec: - packageName: coastal - upgradeConstraintPolicy: Enforce - version: 1.0.x -status: - conditions: - - lastTransitionTime: "2023-11-27T20:34:53Z" - message: installed from "docker.io/bpalmer/coastal-bundle:v1.0.0" - observedGeneration: 1 - reason: Success - status: "True" - type: Installed - - lastTransitionTime: "2023-11-27T20:34:49Z" - message: resolved to "docker.io/bpalmer/coastal-bundle:v1.0.0" - observedGeneration: 1 - reason: Success - status: "True" - type: Resolved - installedBundleResource: docker.io/bpalmer/coastal-bundle:v1.0.0 - resolvedBundleResource: docker.io/bpalmer/coastal-bundle:v1.0.0 -``` - -
- -and for the `Catalog` with: -```sh -kubectl get catalog/coastal -o yaml -w -``` - -
-Example - -```yaml -apiVersion: catalogd.operatorframework.io/v1alpha1 -kind: Catalog -metadata: - annotations: - kubectl.kubernetes.io/last-applied-configuration: | - {"apiVersion":"catalogd.operatorframework.io/v1alpha1","kind":"Catalog","metadata":{"annotations":{},"name":"coastal"},"spec":{"source":{"image":{"pollInterval":"15s","ref":"docker.io/bpalmer/coastal-catalog:latest"},"type":"image"}}} - creationTimestamp: "2023-11-27T20:23:55Z" - finalizers: - - catalogd.operatorframework.io/delete-server-cache - generation: 1 - name: coastal - resourceVersion: "4173" - uid: 0bb0ca54-bdfe-4c55-abeb-03b8e3f32374 -spec: - source: - image: - pollInterval: 15s - ref: docker.io/bpalmer/coastal-catalog:latest - type: image -status: - conditions: - - lastTransitionTime: "2023-11-27T20:23:57Z" - message: "" - reason: UnpackSuccessful - status: "True" - type: Unpacked - contentURL: http://catalogd-catalogserver.catalogd-system.svc/catalogs/coastal/all.json - observedGeneration: 1 - phase: Unpacked - resolvedSource: - image: - lastPollAttempt: "2023-11-27T20:36:22Z" - ref: docker.io/bpalmer/coastal-catalog:latest - resolvedRef: index.docker.io/bpalmer/coastal-catalog@sha256:b8cb9a4a61f57b59394047cab94f5b4ef1083493809f8180125faedaab17c71d - type: image -``` - -
- -Once the `ClusterExtension` has been successfully installed we can verify that all the resources created are healthy by checking the `BundleDeployment` resource owned by the `ClusterExtension` we created. Verify the `BundleDeployment` has a status condition showing whether or not it is healthy with: -```sh -kubectl get bundledeployment/coastal -o yaml -w -``` - -
-Example - -```yaml -apiVersion: core.rukpak.io/v1alpha1 -kind: BundleDeployment -metadata: - creationTimestamp: "2023-11-27T20:34:49Z" - generation: 2 - name: coastal - ownerReferences: - - apiVersion: olm.operatorframework.io/v1alpha1 - blockOwnerDeletion: true - controller: true - kind: ClusterExtension - name: coastal - uid: 48d16240-edae-4904-bad8-58137bebcf8a - resourceVersion: "3935" - uid: 7e487080-15c3-4e56-8789-9a9b516e98b7 -spec: - provisionerClassName: core-rukpak-io-plain - template: - metadata: {} - spec: - provisionerClassName: core-rukpak-io-plain - source: - image: - ref: docker.io/bpalmer/coastal-bundle:v1.0.0 - type: image -status: - activeBundle: coastal-v725xf - conditions: - - lastTransitionTime: "2023-11-27T20:34:49Z" - message: Successfully unpacked the coastal-v725xf Bundle - reason: UnpackSuccessful - status: "True" - type: HasValidBundle - - lastTransitionTime: "2023-11-27T20:34:53Z" - message: Instantiated bundle coastal-v725xf successfully - reason: InstallationSucceeded - status: "True" - type: Installed - - lastTransitionTime: "2023-11-27T20:35:04Z" - message: BundleDeployment is healthy - reason: Healthy - status: "True" - type: Healthy - observedGeneration: 2 -``` - -
- -### Update the FBC Image to contain a bundle for `v1.1.0` -Let's ensure that adding a bundle with a version of `v1.1.0` does not trigger an upgrade. - -- Add the new bundle to the catalog YAML file -```sh -cat << EOF >> catalog/index.yaml ---- -schema: olm.bundle -name: coastal.v1.1.0 -package: coastal -image: quay.io/operator-framework/coastal-bundle:v1.1.0 -properties: - - type: olm.package - value: - packageName: coastal - version: 1.1.0 - - type: olm.bundle.mediatype - value: plain+v0 -EOF -``` - -- Using `yq`, update the channel to include this bundle as an entry -```sh -yq eval 'select(.schema=="olm.channel" and .name == "stable").entries += [{"name" : "coastal.v1.1.0"}]' -i catalog/index.yaml -``` - -- Build and push the catalog image -```sh -docker build -t quay.io/operator-framework/coastal-catalog:latest -f catalog.Dockerfile . && \ -docker push quay.io/operator-framework/coastal-catalog:latest -``` - -Similar to the previous procedure, the `Catalog` updates its resolved reference, -but the `ClusterExtension` resource remains the same and does not -automatically upgrade to `v1.1.0` - -### Update the FBC Image to contain a bundle for `v1.0.1` -Lets add the `v1.0.1` bundle to our catalog -and ensure it automatically upgrades within the z-stream. - -- Add the new bundle to the catalog YAML file -```sh -cat << EOF >> catalog/index.yaml ---- -schema: olm.bundle -name: coastal.v1.0.1 -package: coastal -image: quay.io/operator-framework/coastal-bundle:v1.0.1 -properties: - - type: olm.package - value: - packageName: coastal - version: 1.0.1 - - type: olm.bundle.mediatype - value: plain+v0 -EOF -``` - -- Using `yq`, update the channel to include this bundle as an entry -```sh -yq eval 'select(.schema=="olm.channel" and .name == "stable").entries += [{"name" : "coastal.v1.0.1"}]' -i catalog/index.yaml -``` - -- Build and push the catalog image -```sh -docker build -t quay.io/operator-framework/coastal-catalog:latest -f catalog.Dockerfile . && \ -docker push quay.io/operator-framework/coastal-catalog:latest -``` - -Once again, we should see the `Catalog` update its resolved reference. This time, we expect that the `ClusterExtension` resource is automatically upgraded to the new `v1.0.1` bundle we added. - -
-Example Catalog - -```yaml -apiVersion: catalogd.operatorframework.io/v1alpha1 -kind: Catalog -metadata: - annotations: - kubectl.kubernetes.io/last-applied-configuration: | - {"apiVersion":"catalogd.operatorframework.io/v1alpha1","kind":"Catalog","metadata":{"annotations":{},"name":"coastal"},"spec":{"source":{"image":{"pollInterval":"15s","ref":"docker.io/bpalmer/coastal-catalog:latest"},"type":"image"}}} - creationTimestamp: "2023-11-27T20:23:55Z" - finalizers: - - catalogd.operatorframework.io/delete-server-cache - generation: 1 - name: coastal - resourceVersion: "4776" - uid: 0bb0ca54-bdfe-4c55-abeb-03b8e3f32374 -spec: - source: - image: - pollInterval: 15s - ref: docker.io/bpalmer/coastal-catalog:latest - type: image -status: - conditions: - - lastTransitionTime: "2023-11-27T20:23:57Z" - message: "" - reason: UnpackSuccessful - status: "True" - type: Unpacked - contentURL: http://catalogd-catalogserver.catalogd-system.svc/catalogs/coastal/all.json - observedGeneration: 1 - phase: Unpacked - resolvedSource: - image: - lastPollAttempt: "2023-11-27T20:39:45Z" - ref: docker.io/bpalmer/coastal-catalog:latest - resolvedRef: index.docker.io/bpalmer/coastal-catalog@sha256:8affa0e6ca81e07bb9d03b934173687f63015d8b36fac3ba3391a942b23cc3ee - type: image -``` - -
- -
-Example ClusterExtension - -```yaml -apiVersion: olm.operatorframework.io/v1alpha1 -kind: ClusterExtension -metadata: - annotations: - kubectl.kubernetes.io/last-applied-configuration: | - {"apiVersion":"olm.operatorframework.io/v1alpha1","kind":"ClusterExtension","metadata":{"annotations":{},"name":"coastal"},"spec":{"packageName":"coastal","version":"1.0.x"}} - creationTimestamp: "2023-11-27T20:29:18Z" - generation: 1 - name: coastal - resourceVersion: "4778" - uid: 48d16240-edae-4904-bad8-58137bebcf8a -spec: - packageName: coastal - upgradeConstraintPolicy: Enforce - version: 1.0.x -status: - conditions: - - lastTransitionTime: "2023-11-27T20:34:53Z" - message: installed from "docker.io/bpalmer/coastal-bundle:v1.0.1" - observedGeneration: 1 - reason: Success - status: "True" - type: Installed - - lastTransitionTime: "2023-11-27T20:34:49Z" - message: resolved to "docker.io/bpalmer/coastal-bundle:v1.0.1" - observedGeneration: 1 - reason: Success - status: "True" - type: Resolved - installedBundleResource: docker.io/bpalmer/coastal-bundle:v1.0.1 - resolvedBundleResource: docker.io/bpalmer/coastal-bundle:v1.0.1 -``` - -
- -## Change version range to pin installs/upgrades to `v1.1.z` releases -Making changes to the `ClusterExtension` resource should result in a re-reconciliation of the resource -which should result in another resolution loop. To see this, let's update the version range -on our `ClusterExtension` resource to `1.1.x` with: -```sh -kubectl apply -f - < -Example - -```yaml -apiVersion: olm.operatorframework.io/v1alpha1 -kind: ClusterExtension -metadata: - annotations: - kubectl.kubernetes.io/last-applied-configuration: | - {"apiVersion":"olm.operatorframework.io/v1alpha1","kind":"ClusterExtension","metadata":{"annotations":{},"name":"coastal"},"spec":{"packageName":"coastal","version":"1.1.x"}} - creationTimestamp: "2023-11-27T20:29:18Z" - generation: 2 - name: coastal - resourceVersion: "5251" - uid: 48d16240-edae-4904-bad8-58137bebcf8a -spec: - packageName: coastal - upgradeConstraintPolicy: Enforce - version: 1.1.x -status: - conditions: - - lastTransitionTime: "2023-11-27T20:34:53Z" - message: installed from "docker.io/bpalmer/coastal-bundle:v1.1.0" - observedGeneration: 2 - reason: Success - status: "True" - type: Installed - - lastTransitionTime: "2023-11-27T20:34:49Z" - message: resolved to "docker.io/bpalmer/coastal-bundle:v1.1.0" - observedGeneration: 2 - reason: Success - status: "True" - type: Resolved - installedBundleResource: docker.io/bpalmer/coastal-bundle:v1.1.0 - resolvedBundleResource: docker.io/bpalmer/coastal-bundle:v1.1.0 -``` - - - -## Attempting a major version upgrade by changing the version range -The operator-controller follows semver and prevents automatic upgrades to new major versions when a `ClusterExtension`'s `spec.upgradeConstraintPolicy` is set to `Enforce`. New major versions might -have breaking changes and could cause problems for users. Let's add a new major -version of our bundle to the catalog image and update the version range on the `ClusterExtension`. - -### Update the FBC Image to contain a bundle for `v2.0.0` -- Add the new bundle to the catalog YAML file -```sh -cat << EOF >> catalog/index.yaml ---- -schema: olm.bundle -name: coastal.v2.0.0 -package: coastal -image: quay.io/operator-framework/coastal-bundle:v2.0.0 -properties: - - type: olm.package - value: - packageName: coastal - version: 2.0.0 - - type: olm.bundle.mediatype - value: plain+v0 -EOF -``` - -- Using `yq`, update the channel to include this bundle as an entry -```sh -yq eval 'select(.schema=="olm.channel" and .name == "stable").entries += [{"name" : "coastal.v2.0.0"}]' -i catalog/index.yaml -``` - -- Build and push the catalog image -```sh -docker build -t quay.io/operator-framework/coastal-catalog:latest -f catalog.Dockerfile . && \ -docker push quay.io/operator-framework/coastal-catalog:latest -``` - -The `Catalog` updates its resolved reference and no changes are applied to the `ClusterExtension` resource. - -Updating the `ClusterExtension` resource's version range will still result in a resolution failure since the version installed -is a lower major version than specified by the version range. Try it by running: -```sh -kubectl apply -f - < -Example - -```yaml -apiVersion: olm.operatorframework.io/v1alpha1 -kind: ClusterExtension -metadata: - annotations: - kubectl.kubernetes.io/last-applied-configuration: | - {"apiVersion":"olm.operatorframework.io/v1alpha1","kind":"ClusterExtension","metadata":{"annotations":{},"name":"coastal"},"spec":{"packageName":"coastal","version":"2.0.x"}} - creationTimestamp: "2023-11-27T20:29:18Z" - generation: 3 - name: coastal - resourceVersion: "6883" - uid: 48d16240-edae-4904-bad8-58137bebcf8a -spec: - packageName: coastal - upgradeConstraintPolicy: Enforce - version: 2.0.x -status: - conditions: - - lastTransitionTime: "2023-11-27T20:50:27Z" - message: installation has not been attempted as resolution is unsatisfiable - observedGeneration: 3 - reason: InstallationStatusUnknown - status: Unknown - type: Installed - - lastTransitionTime: "2023-11-27T20:50:27Z" - message: |- - constraints not satisfiable: - coastal package uniqueness permits at most 1 of coastal-coastal-coastal.v2.0.0, coastal-coastal-coastal.v1.1.0 - installed package coastal requires at least one of coastal-coastal-coastal.v1.1.0 - installed package coastal is mandatory - required package coastal requires at least one of coastal-coastal-coastal.v2.0.0 - required package coastal is mandatory - observedGeneration: 3 - reason: ResolutionFailed - status: "False" - type: Resolved -``` - - - -## To the escape hatch! -To tell operator-controller to ignore the semver policies and allow upgrades across major versions, -set the `ClusterExtension`'s `spec.upgradeConstraintPolicy` to `Ignore` with: -```sh -kubectl apply -f - < -Example - -```yaml -apiVersion: olm.operatorframework.io/v1alpha1 -kind: ClusterExtension -metadata: - annotations: - kubectl.kubernetes.io/last-applied-configuration: | - {"apiVersion":"olm.operatorframework.io/v1alpha1","kind":"ClusterExtension","metadata":{"annotations":{},"name":"coastal"},"spec":{"packageName":"coastal","upgradeConstraintPolicy":"Ignore","version":"2.0.x"}} - creationTimestamp: "2023-11-27T20:29:18Z" - generation: 4 - name: coastal - resourceVersion: "7338" - uid: 48d16240-edae-4904-bad8-58137bebcf8a -spec: - packageName: coastal - upgradeConstraintPolicy: Ignore - version: 2.0.x -status: - conditions: - - lastTransitionTime: "2023-11-27T20:52:58Z" - message: installed from "docker.io/bpalmer/coastal-bundle:v2.0.0" - observedGeneration: 4 - reason: Success - status: "True" - type: Installed - - lastTransitionTime: "2023-11-27T20:52:58Z" - message: resolved to "docker.io/bpalmer/coastal-bundle:v2.0.0" - observedGeneration: 4 - reason: Success - status: "True" - type: Resolved - installedBundleResource: docker.io/bpalmer/coastal-bundle:v2.0.0 - resolvedBundleResource: docker.io/bpalmer/coastal-bundle:v2.0.0 -``` - - - -## Attempting to downgrade by changing the version range -We can disable downgrades by setting the `ClusterExtension` resource's `spec.UpgradeConstraintPolicy` field to `Enforce`. -To see this, run: -```sh -kubectl apply -f - < -Example - -```yaml -apiVersion: olm.operatorframework.io/v1alpha1 -kind: ClusterExtension -metadata: - annotations: - kubectl.kubernetes.io/last-applied-configuration: | - {"apiVersion":"olm.operatorframework.io/v1alpha1","kind":"ClusterExtension","metadata":{"annotations":{},"name":"coastal"},"spec":{"packageName":"coastal","upgradeConstraintPolicy":"Enforce","version":"1.1.x"}} - creationTimestamp: "2023-11-27T20:29:18Z" - generation: 5 - name: coastal - resourceVersion: "7601" - uid: 48d16240-edae-4904-bad8-58137bebcf8a -spec: - packageName: coastal - upgradeConstraintPolicy: Enforce - version: 1.1.x -status: - conditions: - - lastTransitionTime: "2023-11-27T20:53:55Z" - message: installation has not been attempted as resolution is unsatisfiable - observedGeneration: 5 - reason: InstallationStatusUnknown - status: Unknown - type: Installed - - lastTransitionTime: "2023-11-27T20:53:55Z" - message: |- - constraints not satisfiable: - coastal package uniqueness permits at most 1 of coastal-coastal-coastal.v1.1.0, coastal-coastal-coastal.v2.0.0 - installed package coastal requires at least one of coastal-coastal-coastal.v2.0.0 - installed package coastal is mandatory - required package coastal requires at least one of coastal-coastal-coastal.v1.1.0 - required package coastal is mandatory - observedGeneration: 5 - reason: ResolutionFailed - status: "False" - type: Resolved -``` - - - -## Back to the escape hatch! -To tell operator-controller to ignore the safety mechanisms and downgrade the `ClusterExtension` version, -set the `ClusterExtension`'s `spec.upgradeConstraintPolicy` to `Ignore` with: -```sh -kubectl apply -f - < -Example - -```yaml -apiVersion: olm.operatorframework.io/v1alpha1 -kind: ClusterExtension -metadata: - annotations: - kubectl.kubernetes.io/last-applied-configuration: | - {"apiVersion":"olm.operatorframework.io/v1alpha1","kind":"ClusterExtension","metadata":{"annotations":{},"name":"coastal"},"spec":{"packageName":"coastal","upgradeConstraintPolicy":"Ignore","version":"1.1.x"}} - creationTimestamp: "2023-11-27T20:29:18Z" - generation: 6 - name: coastal - resourceVersion: "7732" - uid: 48d16240-edae-4904-bad8-58137bebcf8a -spec: - packageName: coastal - upgradeConstraintPolicy: Ignore - version: 1.1.x -status: - conditions: - - lastTransitionTime: "2023-11-27T20:54:38Z" - message: installed from "docker.io/bpalmer/coastal-bundle:v1.1.0" - observedGeneration: 6 - reason: Success - status: "True" - type: Installed - - lastTransitionTime: "2023-11-27T20:54:38Z" - message: resolved to "docker.io/bpalmer/coastal-bundle:v1.1.0" - observedGeneration: 6 - reason: Success - status: "True" - type: Resolved - installedBundleResource: docker.io/bpalmer/coastal-bundle:v1.1.0 - resolvedBundleResource: docker.io/bpalmer/coastal-bundle:v1.1.0 -``` - - diff --git a/internal/catalogmetadata/types.go b/internal/catalogmetadata/types.go index e1cb8e2e8..b1d326ee6 100644 --- a/internal/catalogmetadata/types.go +++ b/internal/catalogmetadata/types.go @@ -11,12 +11,6 @@ import ( "github.com/operator-framework/operator-registry/alpha/property" ) -const ( - MediaTypePlain = "plain+v0" - MediaTypeRegistry = "registry+v1" - PropertyBundleMediaType = "olm.bundle.mediatype" -) - type Schemas interface { Package | Bundle | Channel | Deprecation } @@ -50,7 +44,6 @@ type Bundle struct { bundlePackage *property.Package semVersion *bsemver.Version requiredPackages []PackageRequired - mediaType *string } func (b *Bundle) Version() (*bsemver.Version, error) { @@ -67,14 +60,6 @@ func (b *Bundle) RequiredPackages() ([]PackageRequired, error) { return b.requiredPackages, nil } -func (b *Bundle) MediaType() (string, error) { - if err := b.loadMediaType(); err != nil { - return "", err - } - - return *b.mediaType, nil -} - func (b *Bundle) loadPackage() error { b.mu.Lock() defer b.mu.Unlock() @@ -120,19 +105,6 @@ func (b *Bundle) loadRequiredPackages() error { return nil } -func (b *Bundle) loadMediaType() error { - b.mu.Lock() - defer b.mu.Unlock() - if b.mediaType == nil { - mediaType, err := loadOneFromProps[string](b, PropertyBundleMediaType, false) - if err != nil { - return fmt.Errorf("error determining bundle mediatype for bundle %q: %s", b.Name, err) - } - b.mediaType = &mediaType - } - return nil -} - func (b *Bundle) propertiesByType(propType string) []*property.Property { if b.propertiesMap == nil { b.propertiesMap = make(map[string][]*property.Property) diff --git a/internal/catalogmetadata/types_test.go b/internal/catalogmetadata/types_test.go index 3129ecde3..743555de2 100644 --- a/internal/catalogmetadata/types_test.go +++ b/internal/catalogmetadata/types_test.go @@ -2,7 +2,6 @@ package catalogmetadata_test import ( "encoding/json" - "fmt" "testing" bsemver "github.com/blang/semver/v4" @@ -147,61 +146,6 @@ func TestBundleRequiredPackages(t *testing.T) { } } -func TestBundleMediaType(t *testing.T) { - for _, tt := range []struct { - name string - bundle *catalogmetadata.Bundle - wantMediaType string - wantErr string - }{ - { - name: "valid mediatype property", - bundle: &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ - Name: "fake-bundle.v1", - Properties: []property.Property{ - { - Type: catalogmetadata.PropertyBundleMediaType, - Value: json.RawMessage(fmt.Sprintf(`"%s"`, catalogmetadata.MediaTypePlain)), - }, - }, - }}, - wantMediaType: catalogmetadata.MediaTypePlain, - }, - { - name: "no media type provided", - bundle: &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ - Name: "fake-bundle.noMediaType", - Properties: []property.Property{}, - }}, - wantMediaType: "", - }, - { - name: "malformed media type", - bundle: &catalogmetadata.Bundle{Bundle: declcfg.Bundle{ - Name: "fake-bundle.badMediaType", - Properties: []property.Property{ - { - Type: catalogmetadata.PropertyBundleMediaType, - Value: json.RawMessage("badtype"), - }, - }, - }}, - wantMediaType: "", - wantErr: `error determining bundle mediatype for bundle "fake-bundle.badMediaType": property "olm.bundle.mediatype" with value "badtype" could not be parsed: invalid character 'b' looking for beginning of value`, - }, - } { - t.Run(tt.name, func(t *testing.T) { - mediaType, err := tt.bundle.MediaType() - assert.Equal(t, tt.wantMediaType, mediaType) - if tt.wantErr != "" { - assert.EqualError(t, err, tt.wantErr) - } else { - assert.NoError(t, err) - } - }) - } -} - func TestBundleHasDeprecation(t *testing.T) { for _, tt := range []struct { name string diff --git a/internal/controllers/clusterextension_controller.go b/internal/controllers/clusterextension_controller.go index 56575fbad..75109a228 100644 --- a/internal/controllers/clusterextension_controller.go +++ b/internal/controllers/clusterextension_controller.go @@ -135,25 +135,16 @@ func (r *ClusterExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alp // TODO: Question - Should we set the deprecation statuses after we have successfully resolved instead of after a successful installation? - mediaType, err := bundle.MediaType() - if err != nil { - setInstalledStatusConditionFailed(&ext.Status.Conditions, err.Error(), ext.GetGeneration()) - setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration()) - return ctrl.Result{}, err - } - if err := r.validateBundle(bundle); err != nil { setInstalledStatusConditionFailed(&ext.Status.Conditions, err.Error(), ext.GetGeneration()) setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration()) return ctrl.Result{}, err } - bundleProvisioner, err := mapBundleMediaTypeToBundleProvisioner(mediaType) - if err != nil { - setInstalledStatusConditionFailed(&ext.Status.Conditions, err.Error(), ext.GetGeneration()) - setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration()) - return ctrl.Result{}, err - } + // Assume all bundles are registry+v1 for now, since that's all we support. + // If the bundle is not a registry+v1 bundle, the conversion will fail. + bundleProvisioner := "core-rukpak-io-registry" + // Ensure a BundleDeployment exists with its bundle source from the bundle // image we just looked up in the solution. dep := r.GenerateExpectedBundleDeployment(*ext, bundle.Image, bundleProvisioner) @@ -523,23 +514,6 @@ func (r *ClusterExtensionReconciler) existingBundleDeploymentUnstructured(ctx co return &unstructured.Unstructured{Object: unstrExistingBundleDeploymentObj}, nil } -// mapBundleMediaTypeToBundleProvisioner maps an olm.bundle.mediatype property to a -// rukpak bundle provisioner class name that is capable of unpacking the bundle type -func mapBundleMediaTypeToBundleProvisioner(mediaType string) (string, error) { - switch mediaType { - case catalogmetadata.MediaTypePlain: - return "core-rukpak-io-plain", nil - // To ensure compatibility with bundles created with OLMv0 where the - // olm.bundle.mediatype property doesn't exist, we assume that if the - // property is empty (i.e doesn't exist) that the bundle is one created - // with OLMv0 and therefore should use the registry provisioner - case catalogmetadata.MediaTypeRegistry, "": - return "core-rukpak-io-registry", nil - default: - return "", fmt.Errorf("unknown bundle mediatype: %s", mediaType) - } -} - // Generate reconcile requests for all cluster extensions affected by a catalog change func clusterExtensionRequestsForCatalog(c client.Reader, logger logr.Logger) handler.MapFunc { return func(ctx context.Context, _ client.Object) []reconcile.Request { diff --git a/internal/controllers/clusterextension_controller_test.go b/internal/controllers/clusterextension_controller_test.go index 418bd4a0e..f5f389514 100644 --- a/internal/controllers/clusterextension_controller_test.go +++ b/internal/controllers/clusterextension_controller_test.go @@ -909,116 +909,6 @@ func TestClusterExtensionNoVersion(t *testing.T) { require.NoError(t, cl.DeleteAllOf(ctx, &rukpakv1alpha2.BundleDeployment{})) } -func TestClusterExtensionPlainV0Bundle(t *testing.T) { - cl, reconciler := newClientAndReconciler(t) - ctx := context.Background() - extKey := types.NamespacedName{Name: fmt.Sprintf("cluster-extension-test-%s", rand.String(8))} - - t.Log("When the cluster extension specifies a package with a plain+v0 bundle") - t.Log("By initializing cluster state") - pkgName := "plain" - pkgVer := "0.1.0" - pkgChan := "beta" - clusterExtension := &ocv1alpha1.ClusterExtension{ - ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, - Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: pkgName, - Version: pkgVer, - Channel: pkgChan, - InstallNamespace: "default", - }, - } - require.NoError(t, cl.Create(ctx, clusterExtension)) - - t.Log("It sets resolution success status") - t.Log("By running reconcile") - res, err := reconciler.Reconcile(ctx, ctrl.Request{NamespacedName: extKey}) - require.Equal(t, ctrl.Result{}, res) - require.NoError(t, err) - - t.Log("By fetching updated cluster extension after reconcile") - require.NoError(t, cl.Get(ctx, extKey, clusterExtension)) - - t.Log("By checking the status fields") - require.Equal(t, &ocv1alpha1.BundleMetadata{Name: "operatorhub/plain/0.1.0", Version: "0.1.0"}, clusterExtension.Status.ResolvedBundle) - require.Empty(t, clusterExtension.Status.InstalledBundle) - t.Log("By checking the expected conditions") - cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1alpha1.TypeResolved) - require.NotNil(t, cond) - require.Equal(t, metav1.ConditionTrue, cond.Status) - require.Equal(t, ocv1alpha1.ReasonSuccess, cond.Reason) - require.Equal(t, "resolved to \"quay.io/operatorhub/plain@sha256:plain\"", cond.Message) - cond = apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1alpha1.TypeInstalled) - require.NotNil(t, cond) - require.Equal(t, metav1.ConditionUnknown, cond.Status) - require.Equal(t, ocv1alpha1.ReasonInstallationStatusUnknown, cond.Reason) - require.Equal(t, "bundledeployment status is unknown", cond.Message) - - t.Log("By fetching the bundled deployment") - bd := &rukpakv1alpha2.BundleDeployment{} - require.NoError(t, cl.Get(ctx, types.NamespacedName{Name: extKey.Name}, bd)) - require.Equal(t, "core-rukpak-io-plain", bd.Spec.ProvisionerClassName) - require.Equal(t, rukpakv1alpha2.SourceTypeImage, bd.Spec.Source.Type) - require.NotNil(t, bd.Spec.Source.Image) - require.Equal(t, "quay.io/operatorhub/plain@sha256:plain", bd.Spec.Source.Image.Ref) - - verifyInvariants(ctx, t, reconciler.Client, clusterExtension) - require.NoError(t, cl.DeleteAllOf(ctx, &ocv1alpha1.ClusterExtension{})) - require.NoError(t, cl.DeleteAllOf(ctx, &rukpakv1alpha2.BundleDeployment{})) -} - -func TestClusterExtensionBadBundleMediaType(t *testing.T) { - cl, reconciler := newClientAndReconciler(t) - ctx := context.Background() - extKey := types.NamespacedName{Name: fmt.Sprintf("cluster-extension-test-%s", rand.String(8))} - - t.Log("When the cluster extension specifies a package with a bad bundle mediatype") - t.Log("By initializing cluster state") - pkgName := "badmedia" - pkgVer := "0.1.0" - pkgChan := "beta" - clusterExtension := &ocv1alpha1.ClusterExtension{ - ObjectMeta: metav1.ObjectMeta{Name: extKey.Name}, - Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: pkgName, - Version: pkgVer, - Channel: pkgChan, - InstallNamespace: "default", - }, - } - require.NoError(t, cl.Create(ctx, clusterExtension)) - - t.Log("It sets resolution success status") - t.Log("By running reconcile") - res, err := reconciler.Reconcile(ctx, ctrl.Request{NamespacedName: extKey}) - require.Equal(t, ctrl.Result{}, res) - require.Error(t, err) - require.ErrorContains(t, err, "unknown bundle mediatype: badmedia+v1") - - t.Log("By fetching updated cluster extension after reconcile") - require.NoError(t, cl.Get(ctx, extKey, clusterExtension)) - - t.Log("By checking the status fields") - require.Equal(t, &ocv1alpha1.BundleMetadata{Name: "operatorhub/badmedia/0.1.0", Version: "0.1.0"}, clusterExtension.Status.ResolvedBundle) - require.Empty(t, clusterExtension.Status.InstalledBundle) - - t.Log("By checking the expected conditions") - cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1alpha1.TypeResolved) - require.NotNil(t, cond) - require.Equal(t, metav1.ConditionTrue, cond.Status) - require.Equal(t, ocv1alpha1.ReasonSuccess, cond.Reason) - require.Equal(t, "resolved to \"quay.io/operatorhub/badmedia@sha256:badmedia\"", cond.Message) - cond = apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1alpha1.TypeInstalled) - require.NotNil(t, cond) - require.Equal(t, metav1.ConditionFalse, cond.Status) - require.Equal(t, ocv1alpha1.ReasonInstallationFailed, cond.Reason) - require.Equal(t, "unknown bundle mediatype: badmedia+v1", cond.Message) - - verifyInvariants(ctx, t, reconciler.Client, clusterExtension) - require.NoError(t, cl.DeleteAllOf(ctx, &ocv1alpha1.ClusterExtension{})) - require.NoError(t, cl.DeleteAllOf(ctx, &rukpakv1alpha2.BundleDeployment{})) -} - func verifyInvariants(ctx context.Context, t *testing.T, c client.Client, ext *ocv1alpha1.ClusterExtension) { key := client.ObjectKeyFromObject(ext) require.NoError(t, c.Get(ctx, key, ext)) @@ -2000,18 +1890,6 @@ var ( }, }, } - plainBetaChannel = catalogmetadata.Channel{ - Channel: declcfg.Channel{ - Name: "beta", - Package: "plain", - }, - } - badmediaBetaChannel = catalogmetadata.Channel{ - Channel: declcfg.Channel{ - Name: "beta", - Package: "badmedia", - }, - } ) var testBundleList = []*catalogmetadata.Bundle{ @@ -2080,32 +1958,4 @@ var testBundleList = []*catalogmetadata.Bundle{ CatalogName: "fake-catalog", InChannels: []*catalogmetadata.Channel{&prometheusBetaChannel}, }, - { - Bundle: declcfg.Bundle{ - Name: "operatorhub/plain/0.1.0", - Package: "plain", - Image: "quay.io/operatorhub/plain@sha256:plain", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName":"plain","version":"0.1.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[]`)}, - {Type: "olm.bundle.mediatype", Value: json.RawMessage(`"plain+v0"`)}, - }, - }, - CatalogName: "fake-catalog", - InChannels: []*catalogmetadata.Channel{&plainBetaChannel}, - }, - { - Bundle: declcfg.Bundle{ - Name: "operatorhub/badmedia/0.1.0", - Package: "badmedia", - Image: "quay.io/operatorhub/badmedia@sha256:badmedia", - Properties: []property.Property{ - {Type: property.TypePackage, Value: json.RawMessage(`{"packageName":"badmedia","version":"0.1.0"}`)}, - {Type: property.TypeGVK, Value: json.RawMessage(`[]`)}, - {Type: "olm.bundle.mediatype", Value: json.RawMessage(`"badmedia+v1"`)}, - }, - }, - CatalogName: "fake-catalog", - InChannels: []*catalogmetadata.Channel{&badmediaBetaChannel}, - }, } diff --git a/internal/controllers/extension_controller.go b/internal/controllers/extension_controller.go index 5c69eb5cf..82fb22422 100644 --- a/internal/controllers/extension_controller.go +++ b/internal/controllers/extension_controller.go @@ -164,31 +164,7 @@ func (r *ExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alpha1.Ext ext.Status.ResolvedBundle = bundleMetadataFor(bundle) setResolvedStatusConditionSuccess(&ext.Status.Conditions, fmt.Sprintf("resolved to %q", bundle.Image), ext.GetGeneration()) - mediaType, err := bundle.MediaType() - if err != nil { - if c := apimeta.FindStatusCondition(ext.Status.Conditions, ocv1alpha1.TypeInstalled); c == nil { - ext.Status.InstalledBundle = nil - setInstalledStatusConditionFailed(&ext.Status.Conditions, fmt.Sprintf("failed to read bundle mediaType: %v", err), ext.GetGeneration()) - setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration()) - } - setProgressingStatusConditionFailed(&ext.Status.Conditions, fmt.Sprintf("failed to read bundle mediaType: %v", err), ext.GetGeneration()) - return ctrl.Result{}, err - } - - // TODO: this needs to include the registryV1 bundle option. As of this PR, this only supports direct - // installation of a set of manifests. - if mediaType != catalogmetadata.MediaTypePlain { - if c := apimeta.FindStatusCondition(ext.Status.Conditions, ocv1alpha1.TypeInstalled); c == nil { - // Set the TypeInstalled condition to Failed to indicate that the resolution - // hasn't been attempted yet, due to the spec being invalid. - ext.Status.InstalledBundle = nil - setInstalledStatusConditionFailed(&ext.Status.Conditions, fmt.Sprintf("bundle type %s not supported currently", mediaType), ext.GetGeneration()) - setDeprecationStatusesUnknown(&ext.Status.Conditions, "deprecation checks have not been attempted as installation has failed", ext.GetGeneration()) - } - setProgressingStatusConditionFailed(&ext.Status.Conditions, fmt.Sprintf("bundle type %s not supported currently", mediaType), ext.GetGeneration()) - return ctrl.Result{}, nil - } - + // Right now, we just assume that the bundle is a plain+v0 bundle. app, err := r.GenerateExpectedApp(*ext, bundle) if err != nil { if c := apimeta.FindStatusCondition(ext.Status.Conditions, ocv1alpha1.TypeInstalled); c == nil { diff --git a/test/e2e/cluster_extension_install_test.go b/test/e2e/cluster_extension_install_test.go index 3f2b7df86..d7fc3c300 100644 --- a/test/e2e/cluster_extension_install_test.go +++ b/test/e2e/cluster_extension_install_test.go @@ -121,63 +121,6 @@ func TestClusterExtensionInstallRegistry(t *testing.T) { }, pollDuration, pollInterval) } -func TestClusterExtensionInstallPlain(t *testing.T) { - t.Log("When a cluster extension is installed from a catalog") - t.Log("When the cluster extension bundle format is plain+v0") - - clusterExtension, clusterExtensionName, extensionCatalog := testInit(t) - defer testCleanup(t, extensionCatalog, clusterExtension) - defer getArtifactsOutput(t) - - clusterExtension.Spec = ocv1alpha1.ClusterExtensionSpec{ - PackageName: "plain", - InstallNamespace: "default", - } - t.Log("It resolves the specified package with correct bundle path") - t.Log("By creating the ClusterExtension resource") - require.NoError(t, c.Create(context.Background(), clusterExtension)) - - t.Log("By eventually reporting a successful resolution and bundle path") - require.EventuallyWithT(t, func(ct *assert.CollectT) { - assert.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension)) - assert.Len(ct, clusterExtension.Status.Conditions, 6) - cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1alpha1.TypeResolved) - if !assert.NotNil(ct, cond) { - return - } - assert.Equal(ct, metav1.ConditionTrue, cond.Status) - assert.Equal(ct, ocv1alpha1.ReasonSuccess, cond.Reason) - assert.Contains(ct, cond.Message, "resolved to") - assert.NotEmpty(ct, clusterExtension.Status.ResolvedBundle) - }, pollDuration, pollInterval) - - t.Log("By eventually installing the package successfully") - require.EventuallyWithT(t, func(ct *assert.CollectT) { - assert.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtension.Name}, clusterExtension)) - cond := apimeta.FindStatusCondition(clusterExtension.Status.Conditions, ocv1alpha1.TypeInstalled) - if !assert.NotNil(ct, cond) { - return - } - assert.Equal(ct, metav1.ConditionTrue, cond.Status) - assert.Equal(ct, ocv1alpha1.ReasonSuccess, cond.Reason) - assert.Contains(ct, cond.Message, "installed from") - assert.NotEmpty(ct, clusterExtension.Status.InstalledBundle) - - bd := rukpakv1alpha2.BundleDeployment{} - assert.NoError(ct, c.Get(context.Background(), types.NamespacedName{Name: clusterExtensionName}, &bd)) - isUnpackSuccessful := apimeta.FindStatusCondition(bd.Status.Conditions, rukpakv1alpha2.TypeUnpacked) - if !assert.NotNil(ct, isUnpackSuccessful) { - return - } - assert.Equal(ct, rukpakv1alpha2.ReasonUnpackSuccessful, isUnpackSuccessful.Reason) - installed := apimeta.FindStatusCondition(bd.Status.Conditions, rukpakv1alpha2.TypeInstalled) - if !assert.NotNil(ct, installed) { - return - } - assert.Equal(ct, rukpakv1alpha2.ReasonInstallationSucceeded, installed.Reason) - }, pollDuration, pollInterval) -} - func TestClusterExtensionInstallReResolvesWhenNewCatalog(t *testing.T) { t.Log("When a cluster extension is installed from a catalog") t.Log("It resolves again when a new catalog is available") diff --git a/test/extension-developer-e2e/extension_developer_test.go b/test/extension-developer-e2e/extension_developer_test.go index cb7b5f7d0..4b4bbe219 100644 --- a/test/extension-developer-e2e/extension_developer_test.go +++ b/test/extension-developer-e2e/extension_developer_test.go @@ -32,15 +32,6 @@ func TestExtensionDeveloper(t *testing.T) { require.NoError(t, err) var clusterExtensions = []*ocv1alpha1.ClusterExtension{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "plainv0", - }, - Spec: ocv1alpha1.ClusterExtensionSpec{ - PackageName: os.Getenv("PLAIN_PKG_NAME"), - InstallNamespace: "default", - }, - }, { ObjectMeta: metav1.ObjectMeta{ Name: "registryv1", diff --git a/test/extension-developer-e2e/setup.sh b/test/extension-developer-e2e/setup.sh index d6fb74894..81682ebfe 100755 --- a/test/extension-developer-e2e/setup.sh +++ b/test/extension-developer-e2e/setup.sh @@ -8,13 +8,11 @@ help="setup.sh is used to build extensions using the operator-sdk and build the image + bundle image, and create a FBC image for the following bundle formats: - registry+v1 -- plain+v0 This script will ensure that all images built are loaded onto a KinD cluster with the name specified in the arguments. The following environment variables are required for configuring this script: -- \$CATALOG_IMG - the tag for the catalog image that contains the plain+v0 and registry+v1 bundle. +- \$CATALOG_IMG - the tag for the catalog image that contains the registry+v1 bundle. - \$REG_PKG_NAME - the name of the package for the extension that uses the registry+v1 bundle format. -- \$PLAIN_PKG_NAME - the name of the package for the extension that uses the plain+v0 bundle format. setup.sh also takes 5 arguments. Usage: @@ -43,12 +41,6 @@ if [[ -z "${REG_PKG_NAME}" ]]; then exit 1 fi -if [[ -z "${PLAIN_PKG_NAME}" ]]; then - echo "\$PLAIN_PKG_NAME is required to be set" - echo "${help}" - exit 1 -fi - ######################################## # Setup temp dir and local variables ######################################## @@ -62,9 +54,6 @@ DOMAIN=oc-opdev-e2e.operatorframework.io REG_DIR="${TMP_ROOT}/registry" mkdir -p "${REG_DIR}" -PLAIN_DIR="${TMP_ROOT}/plain" -mkdir -p "${PLAIN_DIR}" - operator_sdk=$1 container_tool=$2 kustomize=$3 @@ -74,12 +63,9 @@ namespace=$6 reg_img="${DOMAIN}/registry:v0.0.1" reg_bundle_img="${DOMAIN}/registry-bundle:v0.0.1" -plain_img="${DOMAIN}/plain:v0.0.1" -plain_bundle_img="${DOMAIN}/plain-bundle:v0.0.1" catalog_img="${CATALOG_IMG}" reg_pkg_name="${REG_PKG_NAME}" -plain_pkg_name="${PLAIN_PKG_NAME}" ######################################## # Create the registry+v1 based extension @@ -104,39 +90,10 @@ plain_pkg_name="${PLAIN_PKG_NAME}" $kind load docker-image "${reg_img}" --name "${kcluster_name}" $kind load docker-image "${reg_bundle_img}" --name "${kcluster_name}" -##################################### -# Create the plain+v0 based extension -# and build + load images -##################################### - -( - cd "${PLAIN_DIR}" && \ - $operator_sdk init --domain="${DOMAIN}" && \ - $operator_sdk create api \ - --group="${DOMAIN}" \ - --version v1alpha1 \ - --kind Plain \ - --resource --controller && \ - make generate manifests && \ - make docker-build IMG="${plain_img}" - mkdir -p manifests && \ - $kustomize build config/default > manifests/manifests.yaml -) - -cat << EOF > "${PLAIN_DIR}"/plainbundle.Dockerfile -FROM scratch -ADD manifests /manifests -EOF - -$container_tool build -t "${plain_bundle_img}" -f "${PLAIN_DIR}"/plainbundle.Dockerfile "${PLAIN_DIR}"/ - -$kind load docker-image "${plain_img}" --name "${kcluster_name}" -$kind load docker-image "${plain_bundle_img}" --name "${kcluster_name}" - -##################################### -# Create the FBC that contains both -# the plain+v0 and registry+v1 extensions -##################################### +############################### +# Create the FBC that contains +# the registry+v1 extensions +############################### cat << EOF > "${TMP_ROOT}"/catalog.Dockerfile FROM scratch @@ -175,39 +132,6 @@ cat < "${TMP_ROOT}"/catalog/index.yaml } ] } -{ - "schema": "olm.package", - "name": "${plain_pkg_name}" -} -{ - "schema": "olm.bundle", - "name": "${plain_pkg_name}.v0.0.1", - "package": "${plain_pkg_name}", - "image": "$plain_bundle_img", - "properties": [ - { - "type": "olm.package", - "value": { - "packageName": "${plain_pkg_name}", - "version": "0.0.1" - } - }, - { - "type": "olm.bundle.mediatype", - "value": "plain+v0" - } - ] -} -{ - "schema": "olm.channel", - "name": "preview", - "package": "${plain_pkg_name}", - "entries": [ - { - "name": "${plain_pkg_name}.v0.0.1" - } - ] -} EOF # Add a .indexignore to make catalogd ignore @@ -262,4 +186,3 @@ kubectl wait --for=condition=Complete -n "${namespace}" jobs/kaniko --timeout=60 # don't have write permissions so they can't be removed unless # we ensure they have the write permissions chmod -R +w "${REG_DIR}/bin" -chmod -R +w "${PLAIN_DIR}/bin" diff --git a/testdata/bundles/plain-v0/plain.v0.1.0/Dockerfile b/testdata/bundles/plain-v0/plain.v0.1.0/Dockerfile deleted file mode 100644 index bd54f66e6..000000000 --- a/testdata/bundles/plain-v0/plain.v0.1.0/Dockerfile +++ /dev/null @@ -1,2 +0,0 @@ -FROM scratch -COPY manifests /manifests \ No newline at end of file diff --git a/testdata/bundles/plain-v0/plain.v0.1.0/manifests/configmap.yaml b/testdata/bundles/plain-v0/plain.v0.1.0/manifests/configmap.yaml deleted file mode 100644 index 268033efa..000000000 --- a/testdata/bundles/plain-v0/plain.v0.1.0/manifests/configmap.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# This configmap was pulled straight from the Kubernetes docs -# and can be found at https://kubernetes.io/docs/concepts/configuration/configmap/ -apiVersion: v1 -kind: ConfigMap -metadata: - name: game-demo -data: - # property-like keys; each key maps to a simple value - player_initial_lives: "3" - ui_properties_file_name: "user-interface.properties" - - # file-like keys - game.properties: | - enemy.types=aliens,monsters - player.maximum-lives=5 - user-interface.properties: | - color.good=purple - color.bad=yellow - allow.textmode=true \ No newline at end of file diff --git a/testdata/catalogs/test-catalog/catalog.yaml b/testdata/catalogs/test-catalog/catalog.yaml index c219cb228..f96a53fa1 100644 --- a/testdata/catalogs/test-catalog/catalog.yaml +++ b/testdata/catalogs/test-catalog/catalog.yaml @@ -59,26 +59,4 @@ properties: - type: olm.package value: packageName: prometheus - version: 2.0.0 ---- -schema: olm.package -name: plain -defaultChannel: beta ---- -schema: olm.channel -name: beta -package: plain -entries: - - name: plain.0.1.0 ---- -schema: olm.bundle -name: plain.0.1.0 -package: plain -image: localhost/testdata/bundles/plain-v0/plain:v0.1.0 -properties: - - type: olm.package - value: - packageName: plain - version: 0.1.0 - - type: olm.bundle.mediatype - value: plain+v0 + version: 2.0.0 \ No newline at end of file