diff --git a/OLM_V1_ADOPTION_FAQ.md b/OLM_V1_ADOPTION_FAQ.md new file mode 100644 index 00000000..56578160 --- /dev/null +++ b/OLM_V1_ADOPTION_FAQ.md @@ -0,0 +1,461 @@ +# OLM v1 Adoption FAQ + +This FAQ is compiled from discussions in the #olm-v1-adoption-for-your-operator Slack channel. + +## Table of Contents + +- [Getting Started & Setup](#getting-started--setup) +- [Install Modes & Namespace Configuration](#install-modes--namespace-configuration) +- [Configuration & Customization](#configuration--customization) +- [Migration from OLMv0](#migration-from-olmv0) +- [Webhooks & Security](#webhooks--security) +- [Operator Behavior Changes](#operator-behavior-changes) +- [Known Limitations](#known-limitations) +- [Testing & Verification](#testing--verification) +- [Timeline & Support](#timeline--support) + +--- + +## Getting Started & Setup + +### How do I enable OLMv1 on my cluster? + +OLMv1 has had feature-driven GA levels. Compare your needed feature against the following matrix. + +| Feature | OCP rel# | Availability | +|---------------------------------------|----------|--------------| +| ClusterExtension API | 4.18 | G | +| ClusterCatalog API | 4.18 | G | +| ClusterExtension Webhooks | 4.21 | G | +| ClusterExtension Single/Own-Namespace | 4.22 | G | + +'G' indicates this feature defaults to enabled and is considered Generally Available. +'T' indicates that this feature defaults to disabled and will be enabled in Tech Preview No Upgrades configuration. + + +### Why am I getting "no bundles found for package" errors? + +Common causes: +1. **Wrong catalog version**: OLMv1 in 4.22 points to `registry.redhat.io/redhat/redhat-operator-index:v4.21` and the desired bundle version exists in the 4.22 catalog +2. **Operator not in catalog**: If your operator isn't GA for the catalog version, create a custom ClusterCatalog pointing to the correct version +3. **Version/channel mismatch**: Verify the version and channel exist in the catalog (or remove those filters from your ClusterExtension) + +Example custom ClusterCatalog: +```yaml +apiVersion: olm.operatorframework.io/v1 +kind: ClusterCatalog +metadata: + name: my-custom-catalog +spec: + source: + type: Image + image: + ref: registry.redhat.io/redhat/redhat-operator-index:v4.21 + pollIntervalMinutes: 10 +``` + +### How do I add custom registry certificates to OLMv1? + +Add certificates to the cluster's trust store via: +- `proxy/cluster` resource +- `image.config.openshift.io/cluster` resource + +Note: Some users reported this didn't work in early versions. Verify your OCP version supports this. + +### Why does OLMv1 select the wrong channel (e.g., dev-preview instead of stable)? + +OLMv1 does not support the `operators.operatorframework.io.bundle.channel.default.v1` annotation. If you require a specific channel to be used, always explicitly specify the channel in your ClusterExtension: + +```yaml +spec: + source: + catalog: + channels: + - stable +``` + +--- + +## Install Modes & Namespace Configuration + +### Does my operator need to support AllNamespaces install mode? + +**Phase 2 (OCP 4.21)**: Conditionally no, SingleNamespace and OwnNamespace are supported via the `config.inline.watchNamespace` field in a limited way. + +**Future**: AllNamespaces is the recommended design pattern, but not mandatory yet. + +## Background + +In OLMv0, use-cases for the Single-/Own-namespace installmodes were to facilitate multiple operator installations (potentially with different versions). +OLMv1 is not going to support these use-cases because APIs/CRDs are cluster-scoped and OLMv1 enforces a single-owner rule on resources. See [OLMv1 Design Decisions](https://operator-framework.github.io/operator-controller/project/olmv1_design_decisions/) and [OLMv1 Single Owner Objects](https://operator-framework.github.io/operator-controller/concepts/single-owner-objects/). + +OLMv1 has _limited support_ for Single-/Own-namespace installmodes using ClusterExtension configuration. If your ClusterExtension +- accepts being installed once on the cluster, +- doesn't expect that API visibility is restricted to `.spec.namespace` or `.spec.config.inline.watchNamespace` namespaces, +- don't rely on being able to watch the designated namespace for CRs, and +- isn't reliant on OLMv0's role aggregation mechanisms +then your operator using SingleNamespace or OwnNamespace InstallMode may be installed by OLMv1 without changes. + +### What install modes can be used in OLMv1? + +| Install Mode | OLMv0 | OLMv1 Phase 2 | +|--------------|-------|---------------| +| AllNamespaces | Supported | Supported | +| OwnNamespace | Supported | Supported (with config) | +| SingleNamespace | Supported | Supported (with config) | +| MultiNamespace | Supported | Not Supported | + +### How do I configure SingleNamespace/OwnNamespace mode? + +Use the inline config with `watchNamespace`: + +```yaml +apiVersion: olm.operatorframework.io/v1 +kind: ClusterExtension +metadata: + name: my-operator +spec: + namespace: my-namespace + serviceAccount: + name: my-operator-installer + config: + configType: Inline + inline: + watchNamespace: my-namespace + source: + sourceType: Catalog + catalog: + packageName: my-operator +``` + +### Can I install the same operator in multiple namespaces? + +**No**. ClusterExtension is cluster-scoped. You cannot install multiple instances of the same operator in different namespaces, even with OwnNamespace mode. This is a design change from OLMv0. Read more in [OLMv1 Design Decisions](https://operator-framework.github.io/operator-controller/project/olmv1_design_decisions/). + +### What if my operator requires an environment variable to run as a spoke cluster? + +In OLMv0, you would patch the Subscription: +```bash +oc patch sub/my-subscription --patch '{"spec":{"config":{"env":[{"name": "KMM_MANAGED", "value": "1"}]}}}' --type=merge +``` + +**OLMv1 equivalent**: This feature is being discussed but is not available yet in Phase 2 trials. Check the current ClusterExtension CRD schema. + +--- + +## Configuration & Customization + +### What's the equivalent of Subscription's spec.config.env in OLMv1? + +As of the discussions, there is **no direct equivalent yet**. The `config.inline` field supports `watchNamespace` but not arbitrary environment variables. This is a known gap being addressed. + +### How do I configure operator-specific settings? + +Currently limited to: +- `watchNamespace` via `config.inline.watchNamespace` +- Service account via `spec.serviceAccount.name` + +For other configurations, you may need to use operator-specific CRs after installation or wait for additional config support. + +--- + +## Migration from OLMv0 + +### How do I upgrade an operator from OLMv0 to OLMv1? + +**Short answer**: Migration/upgrade path is still being designed. + +Current understanding: +- OLMv0 and OLMv1 can coexist on the same cluster +- You cannot install the same operator via OLMv0 and via OLMv1 simultaneously +- Direct upgrade/migration tooling is not yet available + +### Can I run OLMv0 and OLMv1 side-by-side? + +Yes, with limitations. OLMv1 enforces a [Single-Owner Model](https://operator-framework.github.io/operator-controller/concepts/single-owner-objects/) for all resources. OLMv0 does not. This means that OLMv1 will refuse to install an operator (containing a CRD) in a cluster where OLMv0 has already installed it. The reverse is NOT true, i.e. OLMv0 will be happy to install a CSV for a ClusterExtension installed by OLMv1. This can lead to unexpected outcomes and should be avoided. + +### When will OLMv0 be deprecated? + +Based on discussions: +- OLMv0 is in **maintenance mode** and viewed as feature complete +- Deprecation is expected to be announced in OCP 5.Y timeframe, but removal will not occur until OCP 6.0 (earliest) +- Operators should continue supporting OLMv0 for OCP 4.Y, OCP 5.Y + +--- + +## Webhooks & Security + +### Are webhooks supported in OLMv1 prior to OCP 4.21? + +No, and the failure message looks like +``` +message: unsupported bundle: webhookDefinitions are not supported +``` + + +### Why are my privileged pods failing with pod security errors? + +OLMv1 does **not automatically add pod security labels** to namespaces like OLMv0 does. + +OLMv0 adds: +```yaml +metadata: + annotations: + security.openshift.io/scc.podSecurityLabelSync: "true" + openshift.io/sa.scc.mcs: s0:c28,c17 + openshift.io/sa.scc.supplemental-groups: 1000790000/10000 + openshift.io/sa.scc.uid-range: 1000790000/10000 + labels: + pod-security.kubernetes.io/enforce: privileged + pod-security.kubernetes.io/audit: privileged + pod-security.kubernetes.io/warn: privileged +``` + +**Workaround**: Manually label the namespace: +```bash +oc label namespace my-namespace pod-security.kubernetes.io/enforce=privileged +oc label namespace my-namespace pod-security.kubernetes.io/audit=privileged +oc label namespace my-namespace pod-security.kubernetes.io/warn=privileged +oc annotate namespace my-namespace security.openshift.io/scc.podSecurityLabelSync=true +``` + +### Why am I getting webhook certificate errors? + +Example error: +``` +x509: certificate is valid for webhook-service.metallb-system.svc, webhook-service.metallb-system.svc.cluster.local, +not metallb-operator-webhook-server-service.metallb-system.svc +``` + +This may be related to how OLMv1 manages certificates. Check if your operator uses cert-manager or service-ca for webhook certificates. + +--- + +## Operator Behavior Changes + +### Does OLMv1 reconcile operator deployments like OLMv0? + +**Yes**, but using different APIs: +- OLMv0 reconciles based on CSV +- OLMv1 reconciles based on the bundle spec in ClusterExtension + +### Can I modify operator deployments at runtime? + +**No**. OLMv1 reverts deployment changes back to the bundle specification. + +One user reported an infinite loop: +1. Operator creates PVC +2. Operator modifies deployment to mount PVC +3. ClusterExtension reverts deployment to bundle spec +4. Loop repeats + +**Implication**: Deployments should be considered **immutable** under OLMv1. Use operator CRs to configure behavior instead of modifying deployments. + +### What happened to CSV manipulation for testing? + +In OLMv0, QE teams could patch the CSV to: +- Set environment variables +- Scale deployments down +- Test different scenarios + +**OLMv1**: The CSV doesn't exist in the same way. ClusterExtension is the primary resource, but it doesn't support the same level of manipulation. + +**Alternative**: Modify the bundle and rebuild, or use operator-specific CRs for configuration. + +### What happened to OperatorCondition CR? + +OLMv1 does **not create** OperatorCondition CRs or set the `OPERATOR_CONDITION_NAME` environment variable. + +**Use case affected**: Blocking upgrades via OperatorCondition + +**Status**: Alternative mechanism under discussion/development. + +### Why am I getting "cannot set blockOwnerDeletion" errors? + +Example: +``` +configmaps "kieconfigs-7.13.5" is forbidden: cannot set blockOwnerDeletion if an ownerReference +refers to a resource you can't set finalizers on +``` + +This is related to OLMv1 design decisions around ownership. The operator may not have permissions to set certain owner references. + +**Reference**: https://operator-framework.github.io/operator-controller/project/olmv1_design_decisions/ + +### Does OLMv1 respect the console.openshift.io/disable-operand-delete annotation? + +**Status unclear** from discussions. In OLMv0, this was a CSV annotation. The equivalent for OLMv1 may be on ClusterExtension, but needs verification. + +--- + +## Known Limitations + +### What features are NOT supported in OLMv1 Phase 2? + +1. **Dependency management**: OLMv0's dependency APIs are not supported + - No automatic installation of required operators (e.g., cert-manager) + - Users must manually install dependencies + +2. **Arbitrary environment variables**: No equivalent to Subscription's `spec.config.env` (yet) + +3. **MultiNamespace install mode**: Not supported + +4. **Multiple instances**: Cannot install the same CRD multiple times in different namespaces + +5. **UI integration**: _Partially_ complete + - ClusterExtensions may not show in "Installed Operators" UI + - OperatorHub shows operators but installation flow differs + +6. **Upgrade support**: Still being developed + +7. **must-gather integration**: Some operators' must-gather may only look for OLMv0 APIs + +### Can I use OLMv0 dependency features? + +No. If your operator declares dependencies via OLMv0's dependency APIs, those will be ignored in OLMv1. + +**Workaround**: Document dependencies and require manual installation. + +### Is there a replacement for operatorframework.io/bundle-unpack-min-retry-interval? + +**Status unclear**. May be obsolete in OLMv1 or handled differently. + +--- + +## Testing & Verification + +### What do I need to verify for my operator? + +1. **Installation**: Operator installs successfully via ClusterExtension +2. **Functionality**: All operator features work as expected +3. **Operands**: Operator can create and manage its operands +4. **Upgrades**: If supported, test upgrade paths (Phase 2 may not support this yet) + +### Are there Prow CI job examples for OLMv1? + +**Status**: OLMv0 had https://docs.ci.openshift.org/docs/how-tos/testing-operator-sdk-operators/ + +OLMv1 examples are being developed. Check the openshift/release repo for updates. + +### How do I test in CI? + +Options: +1. Use clusterbot with TechPreview enabled +2. Create custom CI jobs based on OCP 4.22+ +3. Wait for official OLMv1 CI job templates + +### My operator passed Phase 2 testing. Does it support OLMv1? + +**Probably, but verify**: +- Installation works +- Functionality works +- You've addressed any known limitations (dependencies, pod security, etc.) + +Even if it works, you may need to document changes or limitations for users. + +### Why isn't my operator visible in OperatorHub on 4.22? + +1. **Catalog mismatch**: OCP 4.22 uses v4.21 catalog by default; your operator may only be in v4.21 +2. **Not GA yet**: Operator hasn't been released for 4.22 +3. **Create custom ClusterCatalog**: Point to the catalog index image containing your operator + +--- + +## Timeline & Support + +### When is OLMv1 available? + +- **OCP 4.18-4.22**: Basic feature support initially, with incremental feature addition (see matrix at top). +- **Future**: TBD when it becomes GA + +### When is OLMv0 deprecated? + +- **Currently**: Maintenance mode +- **Expected deprecation**: Not until OCP5.Y +- **Expected removal**: Not until OCP6.0 +- **Recommendation**: Support both OLMv0 (for 4.22 and earlier) and OLMv1 (for 4.18+) + +### What's required for operators in OCP 4.22? + +- **Must work on OLMv0**: For customers not using TechPreview +- **Should be verified on OLMv1**: To ensure future compatibility +- **Document limitations**: If OLMv1 has different behavior/features + +### Do I need to migrate to OLMv1 immediately? + +**No**. OLMv0 will be supported through at least 2027. However: +- Start testing with OLMv1 now +- Plan for eventual migration +- Consider AllNamespaces design pattern for new operator versions + +### Is OLMv1 meant to be an option or a replacement in OCP 4.21? + +**Option** for now. Operators should continue supporting OLMv0 as the primary installation method for 4.21. + +### What if my operator isn't listed in the tracking `Phase 2` spreadsheet? + +It may not be required for Phase 2 verification, but you should still test it if: +- It will be used on OCP 4.21+ +- It uses webhooks +- It has complex namespace requirements +- It has dependencies + +--- + +## Additional Resources + +- **Verification Guide**: https://docs.google.com/document/d/1UpBLZFGONj-e9aDTvWFdlGKLnaIhTZQr-wOWcs6lGCI/edit +- **Design Decisions**: https://operator-framework.github.io/operator-controller/project/olmv1_design_decisions/ +- **Limitations**: https://operator-framework.github.io/operator-controller/project/olmv1_limitations/ +- **Tracking Spreadsheet**: https://docs.google.com/spreadsheets/d/1Nb5BUNyfMmgzBQdXL4MRJKr1MJBU6H8W3JOmzdSANi8/edit + +--- + +## Common Issues & Solutions + +### Issue: "supported install modes OwnNamespace SingleNamespace do not support targeting all namespaces" + +**Solution**: Add the `watchNamespace` config: +```yaml +spec: + config: + configType: Inline + inline: + watchNamespace: your-namespace +``` + +### Issue: "CustomResourceDefinition already exists in namespace and cannot be managed by operator-controller" + +**Cause**: Trying to install the same operator twice (CRDs are cluster-scoped) + +**Solution**: Uninstall the previous instance or use a different operator + +### Issue: "required field watchNamespace is missing" + +**Solution**: Your bundle's registryv1 configuration requires watchNamespace. Add it to your ClusterExtension: +```yaml +spec: + config: + configType: Inline + inline: + watchNamespace: your-namespace +``` + +### Issue: Operator installed but pods not starting due to security constraints + +**Solution**: Add pod security labels to the namespace (see [Webhooks & Security](#webhooks--security) section) + +### Issue: "would violate PodSecurity restricted:latest: privileged containers" + +**Solution**: Set namespace to privileged pod security level: +```bash +oc label namespace your-namespace pod-security.kubernetes.io/enforce=privileged +``` + +--- + +## Contributing to This FAQ + +This FAQ is based on discussions from the #olm-v1-adoption-for-your-operator Slack channel. If you have updates or corrections, please contribute them back to the community. + +**Last Updated**: 2026-01-22 diff --git a/content/en/docs/Concepts/crds/clusterserviceversion.md b/content/en/docs/Concepts/crds/clusterserviceversion.md index 6ad9b1a3..ab84f2d6 100644 --- a/content/en/docs/Concepts/crds/clusterserviceversion.md +++ b/content/en/docs/Concepts/crds/clusterserviceversion.md @@ -106,3 +106,102 @@ spec: version: v1alpha1 kind: Other ``` +## Release Field + +The `release` field is an optional field in the CSV spec that specifies the packaging version of an operator. It allows operator authors to distinguish between different builds of the same operator version. + +### When to Use the Release Field + +Use the `release` field when you need to make changes to the CSV that don't affect the operator's functionality: + +- Fixing typos in descriptions +- Adding or amending annotations or labels +- Amending examples or documentation +- Producing different builds for different environments + +### Format and Validation + +The `release` field must satisfy the following criteria: +- Composed of dot-separated identifiers containing only alphanumerics and hyphens +- Maximum length of 20 characters +- **Cannot contain build metadata** (the `+` character and everything after it) + +Examples: `1`, `alpha`, `alpha.1`, `beta-1`, `rc.2.0` + +### Example + +```yaml +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + name: memcached-operator-v0.10.0-1 +spec: + version: 0.10.0 + release: "1" # Optional packaging version + displayName: Memcached Operator + description: This is an operator for memcached. + # ... rest of CSV spec +``` + +### Bundle Naming Convention with Release + +When a `release` field is specified, the bundle name must follow the convention: + +``` +-v- +``` + +**Examples:** +- `memcached-operator-v0.10.0-1` +- `memcached-operator-v0.10.0-alpha.1` +- `memcached-operator-v0.10.0-rc.2` + +### Version Ordering + +Bundles are ordered using a composite version that considers both `version` and `release`: + +1. Bundles are first ordered by semantic version +2. For bundles with the same version, those **with** a release are ordered **before** those **without** a release +3. Bundles with the same version and both having releases are ordered from highest to lowest release version + +```mermaid +graph TD + A[Bundle Comparison] --> B{Same Version?} + B -->|No| C[Order by Version] + B -->|Yes| D{Both have Release?} + D -->|No| E{Has Release?} + D -->|Yes| F[Order by Release] + E -->|Bundle A| G[A before B] + E -->|Bundle B| H[B before A] + + style A fill:#e1f5ff + style C fill:#c3e6cb + style F fill:#c3e6cb + style G fill:#c3e6cb + style H fill:#c3e6cb +``` + +**Example versions in ascending order:** +``` +memcached-operator.v0.9.0 # version 0.9.0, no release +memcached-operator.v0.10.0 # version 0.10.0, no release +memcached-operator-v0.10.0-1 # version 0.10.0, release "1" +memcached-operator-v0.10.0-2 # version 0.10.0, release "2" +memcached-operator-v0.10.0-alpha # version 0.10.0, release "alpha" +``` + +### Build Metadata Restriction + +The `release` field **cannot contain build metadata**. The following is **invalid**: + +```yaml +# ❌ INVALID - release cannot contain build metadata (the + character) +version: 0.10.0 +release: "1+fffdb0e" +``` + +```yaml +# ✅ VALID - build metadata can be in version when no release is present +version: 0.10.0+fffdb0e +# no release field +``` \ No newline at end of file diff --git a/content/en/docs/Reference/catalog-templates.md b/content/en/docs/Reference/catalog-templates.md index ad3b4c13..5a430140 100644 --- a/content/en/docs/Reference/catalog-templates.md +++ b/content/en/docs/Reference/catalog-templates.md @@ -141,7 +141,7 @@ opm alpha convert-template basic [flags] -Example template in JSON format after the conversion: +### Example template in JSON format after the conversion ```json { @@ -171,6 +171,61 @@ Example template in JSON format after the conversion: } ``` +## Using existing FBC to bootstrap a Substitutes Template +The `opm` tool provides the capability to generate a substitutes template from existing FBC in JSON or YAML formats. + +### Usage + +```sh +./bin/opm alpha convert-template substitutes [flags] +``` + +| Flag | Description | +| ------------------- | -------------------------------------------------------------------------------------- | +| -h, --help | prints help/usage information | +| -o, --output | the output format, can be `yaml` or `json` | +| --skip-tls-verify | skip TLS certificate verification for container image registries while pulling bundles | +| --use-http | use plain HTTP for container image registries while pulling bundles | + +`--skip-tls-verify` and `--use-http` are mutually exclusive flags. + +### Example template in JSON format after the conversion +>Note: empty substitutions are provided, but must be filled in to be valid + +```json +{ + "schema": "olm.template.substitutes", + "entries": [ + { + "schema": "olm.package", + "name": "hello-kubernetes", + "defaultChannel": "alpha", + "description": "hello-kubernetes" + }, + { + "schema": "olm.channel", + "name": "alpha", + "package": "hello-kubernetes", + "entries": [ + { + "name": "hello-kubernetes.v0.0.1" + } + ] + }, + { + "schema": "olm.bundle", + "image": "docker.io/test/hello-kubernetes-operator-bundle:v0.0.1" + } + ], + "substitutions": [ + { + "name": "", + "base": "" + } + ] +} +``` + ## Semver Template Since a `catalog template` is identified as an input schema which is processed to generate a valid FBC, we can define a `semver template` as a schema which uses channel conventions to facilitate the auto-generation of channels adhering to [Semantic Versioning](https://semver.org/) (semver) guidelines and consistent with best practices on [channel naming](/docs/best-practices/channel-naming/#naming). This approach may be attractive to operator authors who are defining a new upgrade graph, or are already close enough to this template's conventions to be able to adopt it. @@ -511,3 +566,299 @@ package: testoperator schema: olm.channel ``` +## Substitutes Template + +The substitutes template provides a safe and structured way to replace bundles in an upgrade graph with newer packaging versions. This is particularly useful when you need to republish a bundle with non-functional changes (documentation fixes, label updates, etc.) and want to ensure users can upgrade to the new bundle. + +Before the substitutes template, when you needed to replace a bundle in a catalog (for example, `foo.v1.0.0` with a documentation fix), you had two options: + +1. **Manually edit all channel entries** - Error-prone and requires updating multiple references +2. **Use the deprecated `substitutesFor` CSV field** - Not available in file-based catalogs + +The `olm.template.substitutes` template solves this by automatically handling the complex graph mutations required to safely replace bundles. + +### Schema + +```yaml +schema: olm.template.substitutes +entries: + - # Existing FBC catalog content (packages, channels, bundles) +substitutions: + - name: # Bundle image to substitute + base: # Bundle name to replace +``` + +### How It Works + +When you define a substitution: + +1. The template validates that the substitute bundle has a higher composite version than the base bundle +2. For each channel containing the base bundle, the template: + - Adds the new bundle to the channel + - Moves upgrade edges (replaces, skips, skipRange) from the base to the substitute + - Adds a skip edge from substitute to base + - Updates all other entries that reference the base to reference the substitute instead + +Before Substitution +```mermaid +graph LR + A1[foo.v0.9.0] -->|replace| B1[foo.v1.0.0] + B1 -->|replace| C1[foo.v1.1.0] +``` + +After Substitution +```mermaid +graph LR + A2[foo.v0.9.0] -->|replace| B2[foo-v1.0.0-1
NEW] + B2 -->|replace| C2[foo.v1.1.0] + B2 -.->|skip| D2[foo.v1.0.0
OLD] + + style B2 fill:#c3e6cb,stroke:#28a745,stroke-width:3px + style D2 fill:#f8d7da,stroke:#dc3545,stroke-width:2px,stroke-dasharray: 5 5 +``` + +### Step-by-Step Example + +#### Step 1: Initial Catalog State + +You have a catalog with three bundles in the `stable` channel: + +```yaml +--- +schema: olm.channel +package: foo +name: stable +entries: + - name: foo.v0.9.0 + - name: foo.v1.0.0 + replaces: foo.v0.9.0 + - name: foo.v1.1.0 + replaces: foo.v1.0.0 +--- +schema: olm.bundle +package: foo +name: foo.v1.0.0 +image: quay.io/example/foo-bundle:v1.0.0 +properties: + - type: olm.package + value: + packageName: foo + version: 1.0.0 +``` + +#### Step 2: Create New Bundle with Release + +You discover `foo.v1.0.0` is missing a critical annotation. +You: +1. update the bundle's annotation in `metadata/annotations.yaml` +2. update the bundle's CSV with `spec.release` set (here set to 1) +3. ensure that the bundle's `metadata-name` follows the format required for using release versions +4. publish the bundle + +The `opm render`-ed bundle image would look something like this in FBC: + +```yaml +--- +schema: olm.bundle +package: foo +name: foo-v1.0.0-1 # New name with release +image: quay.io/example/foo-bundle:v1.0.0-1 +properties: + - type: olm.package + value: + packageName: foo + version: 1.0.0 + release: "1" # Added release +``` + +#### Step 3: Create Substitutes Template +Instead of manually updating the catalog, create a substitutes template: +> Note: see [Using existing FBC to bootstrap a Substitutes Template](#using-existing-fbc-to-bootstrap-a-substitutes-template) to get `opm` to generate this for you. + +```yaml +schema: olm.template.substitutes +entries: + # Include all your existing catalog content here + # (packages, channels, bundles - except the new foo-v1.0.0-1) +substitutions: + - name: quay.io/example/foo-bundle:v1.0.0-1 # New bundle image + base: foo.v1.0.0 # Old bundle name to replace +``` + +#### Step 4: Render the Template + +Use `opm` to render the template: + +```bash +opm alpha render-template substitutes-template.yaml -o yaml > catalog/foo/index.yaml +``` + +The rendered catalog will have: + +```yaml +--- +schema: olm.channel +package: foo +name: stable +entries: + - name: foo.v0.9.0 + - name: foo-v1.0.0-1 # NEW substitute bundle + replaces: foo.v0.9.0 + skips: + - foo.v1.0.0 # Skips the old bundle + - name: foo.v1.1.0 + replaces: foo-v1.0.0-1 # Updated to point to new bundle + - name: foo.v1.0.0 # OLD bundle remains in catalog + # No upgrade edges (orphaned) +``` + +### Substitution Rules and Validation + +The template enforces several validation rules: + +1. **Composite version check**: The substitute bundle must have a higher composite version than the base bundle + ```yaml + # ✅ VALID - release "1" > no release + base: foo.v1.0.0 (version 1.0.0, no release) + name: foo-v1.0.0-1 (version 1.0.0, release "1") + + # ❌ INVALID - same version and release + base: foo-v1.0.0-1 + name: foo-v1.0.0-1 + + # ❌ INVALID - lower composite version + base: foo-v1.0.0-2 + name: foo-v1.0.0-1 + ``` + +2. **Base bundle must exist**: The base bundle name must be present in the catalog + +3. **Required fields**: Both `name` (bundle image) and `base` (bundle name) are required + +4. **Name vs Base validation**: The `name` and `base` cannot be the same + +#### Multiple Substitutions + +You can define multiple substitutions in a single template: + +```yaml +schema: olm.template.substitutes +entries: + # ... catalog content ... +substitutions: + - name: quay.io/example/foo-bundle:v1.0.0-1 + base: foo.v1.0.0 + - name: quay.io/example/foo-bundle:v1.1.0-1 + base: foo.v1.1.0 + - name: quay.io/example/bar-bundle:v2.0.0-alpha.2 + base: bar-v2.0.0-alpha.1 +``` + +The substitutions are processed in order, and each substitution validates against the current state of the catalog. + +#### Upgrade Path Diagram + +```mermaid +stateDiagram-v2 + [*] --> InstalledOld: User has foo.v1.0.0 + [*] --> InstalledNew: New user installs + + InstalledOld --> UpgradeToSubstitute: Catalog updated with
substitution + InstalledNew --> UseSubstitute: Directly installs
foo-v1.0.0-1 + + UpgradeToSubstitute --> foo_v1_0_0_1: OLM sees substitute
skips old bundle + UseSubstitute --> foo_v1_0_0_1: Gets latest bundle + + foo_v1_0_0_1 --> [*]: Up to date + + note right of UpgradeToSubstitute + Skip relationship ensures + users upgrade to the new + packaging version + end note +``` + +### Best Practices + +1. **Use for packaging changes only**: The substitute bundle should be functionally equivalent to the base bundle + +2. **Validate composite versions**: Ensure your substitute bundle has a higher composite version (typically by adding a release field) + +3. **Test before deploying**: Use `opm validate` to verify the rendered catalog: + ```bash + opm alpha render-template template.yaml | opm validate - + ``` + +4. **Keep base bundles**: The old bundle remains in the catalog but becomes unreachable through normal upgrade paths (it's still accessible for historical reference) + +5. **Document substitutions**: Add comments in your template explaining why each substitution was made + + ```yaml + substitutions: + # Fixed typo in operator description + - name: quay.io/example/foo-bundle:v1.0.0-1 + base: foo.v1.0.0 + ``` + +### Complete Working Example + +```yaml +--- +schema: olm.template.substitutes + +# Your existing catalog content +entries: + - schema: olm.package + name: foo + defaultChannel: stable + + - schema: olm.channel + package: foo + name: stable + entries: + - name: foo.v0.9.0 + - name: foo.v1.0.0 + replaces: foo.v0.9.0 + - name: foo.v1.1.0 + replaces: foo.v1.0.0 + + - schema: olm.bundle + package: foo + name: foo.v0.9.0 + image: quay.io/example/foo-bundle:v0.9.0 + properties: + - type: olm.package + value: + packageName: foo + version: 0.9.0 + + - schema: olm.bundle + package: foo + name: foo.v1.0.0 + image: quay.io/example/foo-bundle:v1.0.0 + properties: + - type: olm.package + value: + packageName: foo + version: 1.0.0 + + - schema: olm.bundle + package: foo + name: foo.v1.1.0 + image: quay.io/example/foo-bundle:v1.1.0 + properties: + - type: olm.package + value: + packageName: foo + version: 1.1.0 + +# Define the substitution +substitutions: + - name: quay.io/example/foo-bundle:v1.0.0-1 # New bundle with fixed docs + base: foo.v1.0.0 # Old bundle to replace +``` + +Render with: +```bash +opm alpha render-template substitutes-template.yaml -o yaml > catalog/foo/index.yaml +``` diff --git a/content/en/docs/Reference/file-based-catalogs.md b/content/en/docs/Reference/file-based-catalogs.md index 458ad57f..1293fc12 100644 --- a/content/en/docs/Reference/file-based-catalogs.md +++ b/content/en/docs/Reference/file-based-catalogs.md @@ -356,8 +356,8 @@ OLM defines a handful of property types, again using the reserved `olm.*` prefix #### `olm.package` An `olm.package` property defines the package name and version. This is a required property on bundles, and there must -be exactly one of these properties. The `packageName` must match the bundle's first-class `package` field, and the -`version` must be a valid [semantic version][semver] +be exactly one of these properties. The `packageName` must match the bundle's first-class `package` field, the +`version` must be a valid [semantic version][semver], and the package may include an optional `release` bundle packaging field. See the [Bundle Release Property](#bundle-release-property) section for additional format requirements and examples. The `olm.package` property [cue][cuelang-spec] schema is: ```cue @@ -366,6 +366,7 @@ The `olm.package` property [cue][cuelang-spec] schema is: value: { packageName: string & !="" version: string & !="" + release?: string & !="" // optional release version } } ``` @@ -640,6 +641,186 @@ The `olm.bundle.object` property [cue][cuelang-spec] schema is: [semver]: https://semver.org/spec/v2.0.0.html [semver-range]: https://github.com/blang/semver/blob/master/README.md#ranges +### Bundle Release Property + +#### `olm.package` with Release Version + +The `olm.package` property has been extended to support an optional `release` field that specifies the packaging version of a bundle. This allows catalog maintainers to distinguish between different builds of the same operator version. +##### Use Cases for Bundle Release + +Use the `release` field when you need to: + +1. **Republish a bundle with documentation fixes** + ```yaml + # Original bundle + name: foo.v0.3.0 + version: 0.3.0 + # (no release) + + # Updated bundle with fixed description + name: foo-v0.3.0-1 + version: 0.3.0 + release: "1" + ``` + +2. **Create environment-specific builds** + ```yaml + # Production build + name: foo-v0.3.0-prod + version: 0.3.0 + release: "prod" + + # Staging build + name: foo-v0.3.0-staging + version: 0.3.0 + release: "staging" + ``` + +3. **Version catalog packaging changes** + ```yaml + # First packaging iteration + name: foo-v0.3.0-1 + version: 0.3.0 + release: "1" + + # Second iteration with label updates + name: foo-v0.3.0-2 + version: 0.3.0 + release: "2" + ``` + +#### Required Bundle Naming with Release + +When the `release` field is present in the `olm.package` property, the bundle name **must** follow this convention: + +``` +-v- +``` + +`opm validate` will fail if the bundle name doesn't match this normalized format. + +**Valid Examples:** +```yaml +# Release is a number +name: foo-v0.3.0-1 +properties: +- type: olm.package + value: + packageName: foo + version: 0.3.0 + release: "1" + +# Release is alphanumeric +name: foo-v0.3.0-alpha.1 +properties: +- type: olm.package + value: + packageName: foo + version: 0.3.0 + release: "alpha.1" +``` + +**Invalid Example:** +```yaml +# ❌ INVALID - name uses dots instead of hyphens +name: foo.v0.3.0.1 +properties: +- type: olm.package + value: + packageName: foo + version: 0.3.0 + release: "1" +``` + +#### Release Format Constraints + +The `release` field: +- Must conform to semver prerelease format (alphanumerics and hyphens, dot-separated) +- **Cannot contain build metadata** (no `+` character) +- Has a maximum length of 20 characters + +**Invalid release values:** +```yaml +# ❌ INVALID - contains build metadata +release: "1+fffdb0e" + +# ❌ INVALID - contains invalid characters +release: "1_beta" +``` + + +#### Example Bundle with Release + +```yaml +schema: olm.bundle +package: foo +name: foo-v0.3.0-1 # Note: name includes release in format -v- + +image: quay.io/example-com/foo-bundle:v0.3.0-1 +properties: +- type: olm.package + value: + packageName: foo + version: 0.3.0 + release: "1" # Optional packaging version +- type: olm.gvk + value: + group: example.com + version: v1alpha1 + kind: Foo +``` + +#### Composite Version Ordering + +Bundles are compared using a **composite version** that combines the `version` and `release`: + +```mermaid +flowchart LR + A[Bundle A] --> AV[version: 0.3.0
release: 1] + B[Bundle B] --> BV[version: 0.3.0
release: 2] + + AV --> C{Compare Versions} + BV --> C + + C -->|Equal| D{Both have
release?} + C -->|Not Equal| E[Order by version] + + D -->|Yes| F[Order by release] + D -->|No| G{Which has
release?} + + G -->|A| H[B < A] + G -->|B| I[A < B] + + F --> J[Bundle A < Bundle B
1 < 2] + + style C fill:#e1f5ff + style D fill:#e1f5ff + style G fill:#e1f5ff + style F fill:#c3e6cb + style E fill:#c3e6cb + style H fill:#c3e6cb + style I fill:#c3e6cb + style J fill:#c3e6cb +``` + +**Ordering rules:** +1. Compare by version first (using semver comparison) +2. If versions are equal: + - Bundles **with** a release are **greater than** bundles **without** a release + - Bundles both having releases are ordered by their release version (using semver prerelease comparison) + +**Example ascending order sequence:** +``` +foo.v0.2.0 # v0.2.0, no release +foo.v0.3.0 # v0.3.0, no release +foo-v0.3.0-1 # v0.3.0, release "1" is greater than no release +foo-v0.3.0-2 # v0.3.0, release "2" is greater than release "1" +foo-v0.3.0-alpha # v0.3.0, release "alpha" is greater than release "2" +foo-v0.3.0-beta.1 # v0.3.0, release "beta.1" is greater than release "alpha" +foo.v0.4.0 # v0.4.0, no release +``` + + ## CLI