apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: my-group
namespace: my-namespace
spec:
targetNamespaces:
- my-namespace
This guide outlines the use of OperatorGroups with the Operator Lifecycle Manager (OLM) in OpenShift Container Platform.
An OperatorGroup is an OLM resource that provides multitenant configuration to OLM-installed Operators. An OperatorGroup selects target namespaces in which to generate required RBAC access for its member Operators.
The set of target namespaces is provided by a comma-delimited string stored in
the ClusterServiceVersion’s (CSV) olm.targetNamespaces
annotation. This
annotation is applied to member Operator’s CSV instances and is projected into
their deployments.
An Operator is considered a member of an OperatorGroup if the following conditions are true:
The Operator’s CSV exists in the same namespace as the OperatorGroup.
The Operator’s CSV’s InstallModes support the set of namespaces targeted by the OperatorGroup.
An InstallMode consists of an InstallModeType
field and a boolean Supported
field. A CSV’s spec can contain a set of InstallModes of four distinct
InstallModeTypes
:
InstallModeType | Description |
---|---|
|
The Operator can be a member of an OperatorGroup that selects its own namespace. |
|
The Operator can be a member of an OperatorGroup that selects one namespace. |
|
The Operator can be a member of an OperatorGroup that selects more than one namespace. |
|
The Operator can be a member of an OperatorGroup that selects all namespaces
(target namespace set is the empty string |
If a CSV’s spec omits an entry of |
You can explicitly name the target namespace for an OperatorGroup using the
spec.targetNamespaces
parameter:
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: my-group
namespace: my-namespace
spec:
targetNamespaces:
- my-namespace
You can alternatively specify a namespace using a label selector with the
spec.selector
parameter:
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: my-group
namespace: my-namespace
spec:
selector:
cool.io/prod: "true"
Listing multiple namespaces via |
If both spec.targetNamespaces
and spec.selector
are defined, spec.selector
is ignored. Alternatively, you can omit both spec.selector
and
spec.targetNamespaces
to specify a global OperatorGroup, which selects all
namespaces:
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: my-group
namespace: my-namespace
The resolved set of selected namespaces is shown in an OperatorGroup’s
status.namespaces
parameter. A global OperatorGroup’s status.namespace
contains
the empty string (""
), which signals to a consuming Operator that it should
watch all namespaces.
Member CSVs of an OperatorGroup have the following annotations:
Annotation | Description |
---|---|
|
Contains the name of the OperatorGroup. |
|
Contains the namespace of the OperatorGroup. |
|
Contains a comma-delimited string that lists the OperatorGroup’s target namespace selection. |
All annotations except |
Information about what GroupVersionKinds
(GVKs) are provided by an
OperatorGroup are shown in an olm.providedAPIs
annotation. The annotation’s
value is a string consisting of <kind>.<version>.<group>
delimited with
commas. The GVKs of CRDs and APIServices provided by all active member CSVs of
an OperatorGroup are included.
Review the following example of an OperatorGroup with a single active member CSV that provides the PackageManifest resource:
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
annotations:
olm.providedAPIs: PackageManifest.v1alpha1.packages.apps.redhat.com
name: olm-operators
namespace: local
...
spec:
selector: {}
serviceAccount:
metadata:
creationTimestamp: null
targetNamespaces:
- local
status:
lastUpdated: 2019-02-19T16:18:28Z
namespaces:
- local
When an OperatorGroup is created, three ClusterRoles are generated. Each contains a single AggregationRule with a ClusterRoleSelector set to match a label, as shown below:
ClusterRole | Label to match |
---|---|
|
|
|
|
|
|
The following RBAC resources are generated when a CSV becomes an active member of an OperatorGroup, as long as the CSV is watching all namespaces with the AllNamespaces
InstallMode and is not in a failed state with reason InterOperatorGroupOwnerConflict
.
ClusterRoles for each API resource from a CRD
ClusterRoles for each API resource from an APIService
Additional Roles and RoleBindings
ClusterRole | Settings |
---|---|
|
Verbs on
Aggregation labels:
|
|
Verbs on
Aggregation labels:
|
|
Verbs on
Aggregation labels:
|
|
Verbs on
Aggregation labels:
|
ClusterRole | Settings |
---|---|
|
Verbs on
Aggregation labels:
|
|
Verbs on
Aggregation labels:
|
|
Verbs on
Aggregation labels:
|
If the CSV defines exactly one target namespace that contains *
, then a
ClusterRole and corresponding ClusterRoleBinding are generated for each
permission defined in the CSV’s permissions field. All resources generated are
given the olm.owner: <csv_name>
and olm.owner.namespace: <csv_namespace>
labels.
If the CSV does not define exactly one target namespace that contains *
,
then all Roles and RoleBindings in the Operator namespace with the
olm.owner: <csv_name>
and olm.owner.namespace: <csv_namespace>
labels are
copied into the target namespace.
OLM creates copies of all active member CSVs of an OperatorGroup in each of that
OperatorGroup’s target namespaces. The purpose of a copied CSV is to tell users
of a target namespace that a specific Operator is configured to watch resources
created there. Copied CSVs have a status reason Copied
and are updated to
match the status of their source CSV. The olm.targetNamespaces
annotation is
stripped from copied CSVs before they are created on the cluster. Omitting the
target namespace selection avoids the duplication of target namespaces between
tenants. Copied CSVs are deleted when their source CSV no longer exists or the
OperatorGroup that their source CSV belongs to no longer targets the copied
CSV’s namespace.
An OperatorGroup is static if its spec.staticProvidedAPIs
field is set to
true
. As a result, OLM does not modify the OperatorGroup’s olm.providedAPIs
annotation, which means that it can be set in advance. This is useful when a
user wants to use an OperatorGroup to prevent resource contention in a set of
namespaces but does not have active member CSVs that provide the APIs for those
resources.
Below is an example of an OperatorGroup that protects Prometheus resources in
all namespaces with the something.cool.io/cluster-monitoring: "true"
annotation:
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: cluster-monitoring
namespace: cluster-monitoring
annotations:
olm.providedAPIs: Alertmanager.v1.monitoring.coreos.com,Prometheus.v1.monitoring.coreos.com,PrometheusRule.v1.monitoring.coreos.com,ServiceMonitor.v1.monitoring.coreos.com
spec:
staticProvidedAPIs: true
selector:
matchLabels:
something.cool.io/cluster-monitoring: "true"
Two OperatorGroups are said to have intersecting provided APIs if the
intersection of their target namespace sets is not an empty set and the
intersection of their provided API sets, defined by olm.providedAPIs
annotations, is not an empty set.
A potential issue is that OperatorGroups with intersecting provided APIs can compete for the same resources in the set of intersecting namespaces.
When checking intersection rules, an OperatorGroup’s namespace is always included as part of its selected target namespaces. |
Each time an active member CSV synchronizes, OLM queries the cluster for the set of intersecting provided APIs between the CSV’s OperatorGroup and all others. OLM then checks if that set is an empty set:
If true
and the CSV’s provided APIs are a subset of the OperatorGroup’s:
Continue transitioning.
If true
and the CSV’s provided APIs are not a subset of the
OperatorGroup’s:
If the OperatorGroup is static:
Clean up any deployments that belong to the CSV.
Transition the CSV to a failed state with status reason
CannotModifyStaticOperatorGroupProvidedAPIs
.
If the OperatorGroup is not static:
Replace the OperatorGroup’s olm.providedAPIs
annotation with the union of
itself and the CSV’s provided APIs.
If false
and the CSV’s provided APIs are not a subset of the
OperatorGroup’s:
Clean up any deployments that belong to the CSV.
Transition the CSV to a failed state with status reason
InterOperatorGroupOwnerConflict
.
If false
and the CSV’s provided APIs are a subset of the OperatorGroup’s:
If the OperatorGroup is static:
Clean up any deployments that belong to the CSV.
Transition the CSV to a failed state with status reason
CannotModifyStaticOperatorGroupProvidedAPIs
.
If the OperatorGroup is not static:
Replace the OperatorGroup’s olm.providedAPIs
annotation with the
difference between itself and the CSV’s provided APIs.
Failure states caused by OperatorGroups are non-terminal. |
The following actions are performed each time an OperatorGroup synchronizes:
The set of provided APIs from active member CSVs is calculated from the cluster. Note that copied CSVs are ignored.
The cluster set is compared to olm.providedAPIs
, and if olm.providedAPIs
contains any extra APIs, then those APIs are pruned.
All CSVs that provide the same APIs across all namespaces are requeued. This notifies conflicting CSVs in intersecting groups that their conflict has possibly been resolved, either through resizing or through deletion of the conflicting CSV.
If more than one OperatorGroup exists in a single namespace, any CSV created
in that namespace will transition to a failure state with the reason
TooManyOperatorGroups
. CSVs in a failed state for this reason will
transition to pending once the number of OperatorGroups in their namespaces
reaches one.
If a CSV’s InstallModes do not support the target namespace selection of the
OperatorGroup in its namespace, the CSV will transition to a failure state
with the reason UnsupportedOperatorGroup
. CSVs in a failed state for this
reason will transition to pending once either the OperatorGroup’s target
namespace selection changes to a supported configuration, or the CSV’s
InstallModes are modified to support the OperatorGroup’s target namespace
selection.