1
0
mirror of https://github.com/openshift/openshift-docs.git synced 2026-02-05 21:46:22 +01:00
Files
openshift-docs/modules/olm-operatorgroups.adoc
2019-09-04 19:30:40 +00:00

434 lines
14 KiB
Plaintext

// Module included in the following assemblies:
//
// * applications/operators/olm-understanding-olm.adoc
[id="olm-operatorgroups_{context}"]
= OperatorGroups
An _OperatorGroup_ is an OLM resource that provides multitenant configuration to
OLM-installed Operators. An OperatorGroup selects a set of 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 CSV's
`olm.targetNamespaces` annotation. This annotation is applied to member
Operator's CSV instances and is projected into their deployments.
[id="olm-operatorgroups-membership_{context}"]
== OperatorGroup membership
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`:
.InstallModes and supported OperatorGroups
[cols="1,2",options="header"]
|===
|InstallModeType |Description
|`OwnNamespace`
|The Operator can be a member of an OperatorGroup that selects its own
namespace.
|`SingleNamespace`
|The Operator can be a member of an OperatorGroup that selects one namespace.
|`MultiNamespace`
|The Operator can be a member of an OperatorGroup that selects more than one
namespace.
|`AllNamespaces`
|The Operator can be a member of an OperatorGroup that selects all namespaces
(target namespace set is the empty string `""`).
|===
[NOTE]
====
If a CSV's spec omits an entry of `InstallModeType`, then that type is
considered unsupported unless support can be inferred by an existing entry that
implicitly supports it.
====
[id="olm-operatorgroups-membership-troubleshooting_{context}"]
=== Troubleshooting OperatorGroup membership
* 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.
[id="olm-operatorgroups-target-namespace_{context}"]
== Target namespace selection
Specify the set of namespaces for the OperatorGroup using a label
selector with the `spec.selector` field:
[source,yaml]
----
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: my-group
namespace: my-namespace
spec:
selector:
matchLabels:
cool.io/prod: "true"
----
You can also explicitly name the target namespaces using the
`spec.targetNamespaces` field:
[source,yaml]
----
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: my-group
namespace: my-namespace
spec:
targetNamespaces:
- my-namespace
- my-other-namespace
- my-other-other-namespace
----
[NOTE]
====
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:
[source,yaml]
----
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` field. A global OperatorGroup's `status.namespace` contains
the empty string (`""`), which signals to a consuming Operator that it should
watch all namespaces.
[id="olm-operatorgroups-csv-annotations_{context}"]
== OperatorGroup CSV annotations
Member CSVs of an OperatorGroup have the following annotations:
[cols="1,1",options="header"]
|===
|Annotation |Description
|`olm.operatorGroup=<group_name>`
|Contains the name of the OperatorGroup.
|`olm.operatorGroupNamespace=<group_namespace>`
|Contains the namespace of the OperatorGroup.
|`olm.targetNamespaces=<target_namespaces>`
|Contains a comma-delimited string that lists the OperatorGroup's target
namespace selection.
|===
[NOTE]
====
All annotations except `olm.targetNamespaces` are included with copied CSVs.
Omitting the `olm.targetNamespaces` annotation on copied CSVs prevents the
duplication of target namespaces between tenants.
====
[id="olm-operatorgroups-provided-apis-annotation_{context}"]
== Provided APIs annotation
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:
[source,yaml]
----
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
----
[id="olm-operatorgroups-rbac_{context}"]
== Role-based access control
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:
[cols="1,1",options="header"]
|===
|ClusterRole |Label to match
|`<operatorgroup_name>-admin`
|`olm.opgroup.permissions/aggregate-to-admin: <operatorgroup_name>`
|`<operatorgroup_name>-edit`
|`olm.opgroup.permissions/aggregate-to-edit: <operatorgroup_name>`
|`<operatorgroup_name>-view`
|`olm.opgroup.permissions/aggregate-to-view: <operatorgroup_name>`
|===
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`.
* xref:olm-resources-per-api-resource-crd_{context}[ClusterRoles for each API resource from a CRD]
* xref:olm-resources-per-api-resource-api_{context}[ClusterRoles for each API resource from an APIService]
* xref:olm-resources-additional-roles-rolebindings_{context}[Additional Roles and RoleBindings]
[id="olm-resources-per-api-resource-crd_{context}"]
.ClusterRoles generated for each API resource from a CRD
[cols="1,1a",options="header"]
|===
|ClusterRole |Settings
|`<kind>.<group>-<version>-admin`
|Verbs on `<kind>`:
* `*`
Aggregation labels:
* `rbac.authorization.k8s.io/aggregate-to-admin: true`
* `olm.opgroup.permissions/aggregate-to-admin: <operatorgroup_name>`
|`<kind>.<group>-<version>-edit`
|Verbs on `<kind>`:
* `create`
* `update`
* `patch`
* `delete`
Aggregation labels:
* `rbac.authorization.k8s.io/aggregate-to-edit: true`
* `olm.opgroup.permissions/aggregate-to-edit: <operatorgroup_name>`
|`<kind>.<group>-<version>-view`
|Verbs on `<kind>`:
* `get`
* `list`
* `watch`
Aggregation labels:
* `rbac.authorization.k8s.io/aggregate-to-view: true`
* `olm.opgroup.permissions/aggregate-to-view: <operatorgroup_name>`
|`<kind>.<group>-<version>-view-crdview`
|Verbs on `apiextensions.k8s.io` `customresourcedefinitions` `<crd-name>`:
* `get`
Aggregation labels:
* `rbac.authorization.k8s.io/aggregate-to-view: true`
* `olm.opgroup.permissions/aggregate-to-view: <operatorgroup_name>`
|===
[id="olm-resources-per-api-resource-api_{context}"]
.ClusterRoles generated for each API resource from an APIService
[cols="1,1a",options="header"]
|===
|ClusterRole |Settings
|`<kind>.<group>-<version>-admin`
|Verbs on `<kind>`:
* `*`
Aggregation labels:
* `rbac.authorization.k8s.io/aggregate-to-admin: true`
* `olm.opgroup.permissions/aggregate-to-admin: <operatorgroup_name>`
|`<kind>.<group>-<version>-edit`
|Verbs on `<kind>`:
* `create`
* `update`
* `patch`
* `delete`
Aggregation labels:
* `rbac.authorization.k8s.io/aggregate-to-edit: true`
* `olm.opgroup.permissions/aggregate-to-edit: <operatorgroup_name>`
|`<kind>.<group>-<version>-view`
|Verbs on `<kind>`:
* `get`
* `list`
* `watch`
Aggregation labels:
* `rbac.authorization.k8s.io/aggregate-to-view: true`
* `olm.opgroup.permissions/aggregate-to-view: <operatorgroup_name>`
|===
[id="olm-resources-additional-roles-rolebindings_{context}"]
.Additional Roles and RoleBindings
* 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.
[id="olm-operatorgroups-copied-csvs_{context}"]
== Copied CSVs
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.
[id="olm-operatorgroups-static_{context}"]
== Static OperatorGroups
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:
[source,yaml]
----
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"
----
[id="olm-operatorgroups-intersection_{context}"]
== OperatorGroup intersection
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.
NOTE: When checking intersection rules, an OperatorGroup's namespace is always
included as part of its selected target namespaces.
[id="olm-operatorgroups-intersection-rules_{context}"]
=== Rules for intersection
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.
[NOTE]
====
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.