Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/v1/clusterextension_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ type ClusterExtensionSpec struct {
// a configuration schema the final manifests will be derived on a best-effort basis. More information on how
// to configure the bundle should be found in its end-user documentation.
//
// <opcon:experimental>
// +optional
Config *ClusterExtensionConfig `json:"config,omitempty"`
}
Expand Down
2 changes: 1 addition & 1 deletion docs/api-reference/olmv1-api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ _Appears in:_
| `serviceAccount` _[ServiceAccountReference](#serviceaccountreference)_ | serviceAccount is a reference to a ServiceAccount used to perform all interactions<br />with the cluster that are required to manage the extension.<br />The ServiceAccount must be configured with the necessary permissions to perform these interactions.<br />The ServiceAccount must exist in the namespace referenced in the spec.<br />serviceAccount is required. | | Required: \{\} <br /> |
| `source` _[SourceConfig](#sourceconfig)_ | source is a required field which selects the installation source of content<br />for this ClusterExtension. Selection is performed by setting the sourceType.<br /><br />Catalog is currently the only implemented sourceType, and setting the<br />sourcetype to "Catalog" requires the catalog field to also be defined.<br /><br />Below is a minimal example of a source definition (in yaml):<br /><br />source:<br /> sourceType: Catalog<br /> catalog:<br /> packageName: example-package | | Required: \{\} <br /> |
| `install` _[ClusterExtensionInstallConfig](#clusterextensioninstallconfig)_ | install is an optional field used to configure the installation options<br />for the ClusterExtension such as the pre-flight check configuration. | | |
| `config` _[ClusterExtensionConfig](#clusterextensionconfig)_ | config is an optional field used to specify bundle specific configuration<br />used to configure the bundle. Configuration is bundle specific and a bundle may provide<br />a configuration schema. When not specified, the default configuration of the resolved bundle will be used.<br /><br />config is validated against a configuration schema provided by the resolved bundle. If the bundle does not provide<br />a configuration schema the final manifests will be derived on a best-effort basis. More information on how<br />to configure the bundle should be found in its end-user documentation. | | |
| `config` _[ClusterExtensionConfig](#clusterextensionconfig)_ | config is an optional field used to specify bundle specific configuration<br />used to configure the bundle. Configuration is bundle specific and a bundle may provide<br />a configuration schema. When not specified, the default configuration of the resolved bundle will be used.<br /><br />config is validated against a configuration schema provided by the resolved bundle. If the bundle does not provide<br />a configuration schema the final manifests will be derived on a best-effort basis. More information on how<br />to configure the bundle should be found in its end-user documentation.<br /><br /><opcon:experimental> | | |


#### ClusterExtensionStatus
Expand Down
25 changes: 24 additions & 1 deletion docs/draft/howto/single-ownnamespace-install.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
## Description

!!! note
The `SingleOwnNamespaceInstallSupport` feature-gate is enabled by default. Use this guide to configure bundles that need Single or Own namespace install modes.
This feature is still in *alpha* the `SingleOwnNamespaceInstallSupport` feature-gate must be enabled to make use of it.
See the instructions below on how to enable it.

---

Expand Down Expand Up @@ -30,6 +31,28 @@ include *installModes*.

[![OwnNamespace Install Demo](https://asciinema.org/a/Rxx6WUwAU016bXFDW74XLcM5i.svg)](https://asciinema.org/a/Rxx6WUwAU016bXFDW74XLcM5i)

## Enabling the Feature-Gate

!!! tip

This guide assumes OLMv1 is already installed. If that is not the case,
you can follow the [getting started](../../getting-started/olmv1_getting_started.md) guide to install OLMv1.

---

Patch the `operator-controller` `Deployment` adding `--feature-gates=SingleOwnNamespaceInstallSupport=true` to the
controller container arguments:

```terminal title="Enable SingleOwnNamespaceInstallSupport feature-gate"
kubectl patch deployment -n olmv1-system operator-controller-controller-manager --type='json' -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--feature-gates=SingleOwnNamespaceInstallSupport=true"}]'
```

Wait for `Deployment` rollout:

```terminal title="Wait for Deployment rollout"
kubectl rollout status -n olmv1-system deployment/operator-controller-controller-manager
```

## Configuring the `ClusterExtension`

A `ClusterExtension` can be configured to install bundle in `Single-` or `OwnNamespace` mode through the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ Then you can query the catalog by using `curl` commands and the `jq` CLI tool to
...
```

!!! important
OLM 1.0 supports installing extensions that define webhooks. Targeting a single or specified set of namespaces requires enabling the `SingleOwnNamespaceInstallSupport` feature-gate.

3. Return list of packages which support `AllNamespaces` install mode, do not use webhooks, and where the channel head version uses `olm.csv.metadata` format:

``` terminal
Expand Down
2 changes: 1 addition & 1 deletion docs/project/olmv1_limitations.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ hide:
Currently, OLM v1 only supports installing operators packaged in [OLM v0 bundles](https://olm.operatorframework.io/docs/tasks/creating-operator-bundle/)
, also known as `registry+v1` bundles. Additionally, the bundled operator, or cluster extension:

* **must** support installation via the `AllNamespaces`, `SingleNamespace`, or `OwnNamespace` install modes.
* **must** support installation via the `AllNamespaces` install mode
* **must not** declare dependencies using any of the following file-based catalog properties:
* `olm.gvk.required`
* `olm.package.required`
Expand Down
3 changes: 3 additions & 0 deletions docs/tutorials/explore-available-content.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ Then you can query the catalog by using `curl` commands and the `jq` CLI tool to
...
```

!!! important
OLM 1.0 supports installing extensions that define webhooks. Targeting a single or specified set of namespaces requires enabling the `SingleOwnNamespaceInstallSupport` feature-gate.

3. Return list of packages that support `AllNamespaces` install mode and do not use webhooks:

``` terminal
Expand Down
23 changes: 18 additions & 5 deletions hack/demo/own-namespace-demo-script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
set -e
trap 'echo "Demo ran into error"; trap - SIGTERM && kill -- -$$; exit 1' ERR SIGINT SIGTERM EXIT

# install standard CRDs
echo "Install standard CRDs..."
kubectl apply -f "$(dirname "${BASH_SOURCE[0]}")/../../manifests/standard.yaml"
# install experimental CRDs with config field support
kubectl apply -f "$(dirname "${BASH_SOURCE[0]}")/../../manifests/experimental.yaml"

# wait for standard CRDs to be available
# wait for experimental CRDs to be available
kubectl wait --for condition=established --timeout=60s crd/clusterextensions.olm.operatorframework.io

# Ensure controller is healthy
# enable 'SingleOwnNamespaceInstallSupport' feature gate
kubectl patch deployment -n olmv1-system operator-controller-controller-manager --type='json' -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--feature-gates=SingleOwnNamespaceInstallSupport=true"}]'

# wait for operator-controller to become available
kubectl rollout status -n olmv1-system deployment/operator-controller-controller-manager

# create install namespace
Expand Down Expand Up @@ -55,6 +57,17 @@ kubectl delete clusterextension argocd-operator --ignore-not-found=true
kubectl delete namespace argocd-system --ignore-not-found=true
kubectl delete clusterrolebinding argocd-installer-crb --ignore-not-found=true

# remove feature gate from deployment
echo "Removing feature gate from operator-controller..."
kubectl patch deployment -n olmv1-system operator-controller-controller-manager --type='json' -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/args", "value": "--feature-gates=SingleOwnNamespaceInstallSupport=true"}]' || true
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The kubectl patch 'remove' operation should not include a 'value' field. The 'remove' operation in JSON Patch only requires the 'path' field, and including 'value' is invalid. This will cause the patch to fail (silently due to '|| true'). The correct operation should remove the specific argument from the array by index or use a different approach.

Suggested change
kubectl patch deployment -n olmv1-system operator-controller-controller-manager --type='json' -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/args", "value": "--feature-gates=SingleOwnNamespaceInstallSupport=true"}]' || true
# Find the index of the last argument in the args array
last_index=$(kubectl get deployment -n olmv1-system operator-controller-controller-manager -o json | jq '.spec.template.spec.containers[0].args | length - 1')
# Remove the last argument (feature gate) from the args array
kubectl patch deployment -n olmv1-system operator-controller-controller-manager --type='json' -p="[{'op': 'remove', 'path': '/spec/template/spec/containers/0/args/${last_index}'}]" || true

Copilot uses AI. Check for mistakes.

# restore standard CRDs
echo "Restoring standard CRDs..."
kubectl apply -f "$(dirname "${BASH_SOURCE[0]}")/../../manifests/base.yaml"

# wait for standard CRDs to be available
kubectl wait --for condition=established --timeout=60s crd/clusterextensions.olm.operatorframework.io

# wait for operator-controller to become available with standard config
kubectl rollout status -n olmv1-system deployment/operator-controller-controller-manager

Expand Down
23 changes: 18 additions & 5 deletions hack/demo/single-namespace-demo-script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
set -e
trap 'echo "Demo ran into error"; trap - SIGTERM && kill -- -$$; exit 1' ERR SIGINT SIGTERM EXIT

# install standard CRDs
echo "Install standard CRDs..."
kubectl apply -f "$(dirname "${BASH_SOURCE[0]}")/../../manifests/standard.yaml"
# install experimental CRDs with config field support
kubectl apply -f "$(dirname "${BASH_SOURCE[0]}")/../../manifests/experimental.yaml"

# wait for standard CRDs to be available
# wait for experimental CRDs to be available
kubectl wait --for condition=established --timeout=60s crd/clusterextensions.olm.operatorframework.io

# Ensure controller is healthy
# enable 'SingleOwnNamespaceInstallSupport' feature gate
kubectl patch deployment -n olmv1-system operator-controller-controller-manager --type='json' -p='[{"op": "add", "path": "/spec/template/spec/containers/0/args/-", "value": "--feature-gates=SingleOwnNamespaceInstallSupport=true"}]'

# wait for operator-controller to become available
kubectl rollout status -n olmv1-system deployment/operator-controller-controller-manager

# create install namespace
Expand Down Expand Up @@ -58,6 +60,17 @@ kubectl delete clusterextension argocd-operator --ignore-not-found=true
kubectl delete namespace argocd-system argocd --ignore-not-found=true
kubectl delete clusterrolebinding argocd-installer-crb --ignore-not-found=true

# remove feature gate from deployment
echo "Removing feature gate from operator-controller..."
kubectl patch deployment -n olmv1-system operator-controller-controller-manager --type='json' -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/args", "value": "--feature-gates=SingleOwnNamespaceInstallSupport=true"}]' || true
Copy link

Copilot AI Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The kubectl patch 'remove' operation should not include a 'value' field. The 'remove' operation in JSON Patch only requires the 'path' field, and including 'value' is invalid. This will cause the patch to fail (silently due to '|| true'). The correct operation should remove the specific argument from the array by index or use a different approach.

Suggested change
kubectl patch deployment -n olmv1-system operator-controller-controller-manager --type='json' -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/args", "value": "--feature-gates=SingleOwnNamespaceInstallSupport=true"}]' || true
kubectl patch deployment -n olmv1-system operator-controller-controller-manager --type='json' -p='[{"op": "remove", "path": "/spec/template/spec/containers/0/args/-"}]' || true

Copilot uses AI. Check for mistakes.

# restore standard CRDs
echo "Restoring standard CRDs..."
kubectl apply -f "$(dirname "${BASH_SOURCE[0]}")/../../manifests/base.yaml"

# wait for standard CRDs to be available
kubectl wait --for condition=established --timeout=60s crd/clusterextensions.olm.operatorframework.io

# wait for operator-controller to become available with standard config
kubectl rollout status -n olmv1-system deployment/operator-controller-controller-manager

Expand Down
1 change: 1 addition & 0 deletions helm/experimental.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ options:
operatorController:
features:
enabled:
- SingleOwnNamespaceInstallSupport
- PreflightPermissions
- HelmChartSupport
- BoxcutterRuntime
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,45 +57,6 @@ spec:
description: spec is an optional field that defines the desired state
of the ClusterExtension.
properties:
config:
description: |-
config is an optional field used to specify bundle specific configuration
used to configure the bundle. Configuration is bundle specific and a bundle may provide
a configuration schema. When not specified, the default configuration of the resolved bundle will be used.

config is validated against a configuration schema provided by the resolved bundle. If the bundle does not provide
a configuration schema the final manifests will be derived on a best-effort basis. More information on how
to configure the bundle should be found in its end-user documentation.
properties:
configType:
description: |-
configType is a required reference to the type of configuration source.

Allowed values are "Inline"

When this field is set to "Inline", the cluster extension configuration is defined inline within the
ClusterExtension resource.
enum:
- Inline
type: string
inline:
description: |-
inline contains JSON or YAML values specified directly in the
ClusterExtension.

inline must be set if configType is 'Inline'.
inline accepts arbitrary JSON/YAML objects.
inline is validation at runtime against the schema provided by the bundle if a schema is provided.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- configType
type: object
x-kubernetes-validations:
- message: inline is required when configType is Inline, and forbidden
otherwise
rule: 'has(self.configType) && self.configType == ''Inline'' ?has(self.inline)
: !has(self.inline)'
install:
description: |-
install is an optional field used to configure the installation options
Expand Down
1 change: 1 addition & 0 deletions helm/tilt.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ options:
operatorController:
features:
enabled:
- SingleOwnNamespaceInstallSupport
- PreflightPermissions
- HelmChartSupport
disabled:
Expand Down
4 changes: 2 additions & 2 deletions internal/operator-controller/features/features.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ var operatorControllerFeatureGates = map[featuregate.Feature]featuregate.Feature
// registry+v1 cluster extensions with single or own namespaces modes
// i.e. with a single watch namespace.
SingleOwnNamespaceInstallSupport: {
Default: true,
PreRelease: featuregate.GA,
Default: false,
PreRelease: featuregate.Alpha,
LockToDefault: false,
},

Expand Down
1 change: 1 addition & 0 deletions manifests/experimental-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2188,6 +2188,7 @@ spec:
- --health-probe-bind-address=:8081
- --metrics-bind-address=:8443
- --leader-elect
- --feature-gates=SingleOwnNamespaceInstallSupport=true
- --feature-gates=PreflightPermissions=true
- --feature-gates=HelmChartSupport=true
- --feature-gates=BoxcutterRuntime=true
Expand Down
1 change: 1 addition & 0 deletions manifests/experimental.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2101,6 +2101,7 @@ spec:
- --health-probe-bind-address=:8081
- --metrics-bind-address=:8443
- --leader-elect
- --feature-gates=SingleOwnNamespaceInstallSupport=true
- --feature-gates=PreflightPermissions=true
- --feature-gates=HelmChartSupport=true
- --feature-gates=BoxcutterRuntime=true
Expand Down
39 changes: 0 additions & 39 deletions manifests/standard-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -648,45 +648,6 @@ spec:
description: spec is an optional field that defines the desired state
of the ClusterExtension.
properties:
config:
description: |-
config is an optional field used to specify bundle specific configuration
used to configure the bundle. Configuration is bundle specific and a bundle may provide
a configuration schema. When not specified, the default configuration of the resolved bundle will be used.

config is validated against a configuration schema provided by the resolved bundle. If the bundle does not provide
a configuration schema the final manifests will be derived on a best-effort basis. More information on how
to configure the bundle should be found in its end-user documentation.
properties:
configType:
description: |-
configType is a required reference to the type of configuration source.

Allowed values are "Inline"

When this field is set to "Inline", the cluster extension configuration is defined inline within the
ClusterExtension resource.
enum:
- Inline
type: string
inline:
description: |-
inline contains JSON or YAML values specified directly in the
ClusterExtension.

inline must be set if configType is 'Inline'.
inline accepts arbitrary JSON/YAML objects.
inline is validation at runtime against the schema provided by the bundle if a schema is provided.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- configType
type: object
x-kubernetes-validations:
- message: inline is required when configType is Inline, and forbidden
otherwise
rule: 'has(self.configType) && self.configType == ''Inline'' ?has(self.inline)
: !has(self.inline)'
install:
description: |-
install is an optional field used to configure the installation options
Expand Down
39 changes: 0 additions & 39 deletions manifests/standard.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -613,45 +613,6 @@ spec:
description: spec is an optional field that defines the desired state
of the ClusterExtension.
properties:
config:
description: |-
config is an optional field used to specify bundle specific configuration
used to configure the bundle. Configuration is bundle specific and a bundle may provide
a configuration schema. When not specified, the default configuration of the resolved bundle will be used.

config is validated against a configuration schema provided by the resolved bundle. If the bundle does not provide
a configuration schema the final manifests will be derived on a best-effort basis. More information on how
to configure the bundle should be found in its end-user documentation.
properties:
configType:
description: |-
configType is a required reference to the type of configuration source.

Allowed values are "Inline"

When this field is set to "Inline", the cluster extension configuration is defined inline within the
ClusterExtension resource.
enum:
- Inline
type: string
inline:
description: |-
inline contains JSON or YAML values specified directly in the
ClusterExtension.

inline must be set if configType is 'Inline'.
inline accepts arbitrary JSON/YAML objects.
inline is validation at runtime against the schema provided by the bundle if a schema is provided.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- configType
type: object
x-kubernetes-validations:
- message: inline is required when configType is Inline, and forbidden
otherwise
rule: 'has(self.configType) && self.configType == ''Inline'' ?has(self.inline)
: !has(self.inline)'
install:
description: |-
install is an optional field used to configure the installation options
Expand Down
Loading
Loading