You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As described in [Event sources and related topics](eventing.md), event sources are the backbone
7
-
for caching resources and triggering the reconciliation for primary resources that are related
8
-
to cached resources.
6
+
As described in [Event sources and related topics](eventing.md) event sources are the backbone
7
+
for caching resources and triggering reconciliation of primary resources related
8
+
to these secondary resources.
9
9
10
-
In the Kubernetes world, the component that does this is called an Informer. Without going into
11
-
the details (there are plenty of good documents online regarding informers), its responsibility
12
-
is to watch resources, cache them, and emit an event if the resource changed.
10
+
In Kubernetes parlance, `Informers` handle that responsibility. Without going into
11
+
the details (there are plenty of good documents online regarding this topics), informers
12
+
watch resources, cache them, and emit an event whenever watched resources change.
13
13
14
-
EventSource is a generalized concept of Informer to non-Kubernetes resources. Thus,
15
-
to cache external resources, and trigger reconciliation if those change.
14
+
`EventSource` generalizes this concept to also cover non-Kubernetes resources. Thus,
15
+
allowing caching of external resources, and triggering reconciliation when those change.
16
16
17
17
## The InformerEventSource
18
18
19
-
The underlying informer implementation comes from the fabric8 client, called [DefaultSharedIndexInformer](https://github.com/fabric8io/kubernetes-client/blob/main/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/informers/impl/DefaultSharedIndexInformer.java).
in Java Operator SDK wraps informers from fabric8 client.
22
-
The purpose of such wrapping is to add additional capabilities required for controllers.
23
-
(In general, Informers are not used only for implementing controllers).
19
+
The underlying informer implementation comes from the Fabric8 client,
20
+
called [DefaultSharedIndexInformer](https://github.com/fabric8io/kubernetes-client/blob/main/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/informers/impl/DefaultSharedIndexInformer.java).
in Java Operator SDK wraps informers from Fabric8 client, thus presenting a unified front to deal with Kubernetes and
23
+
non-Kubernetes resources with the `EventSource` architecture.
24
24
25
-
Such capabilities are:
26
-
- maintaining an index to which primary are the secondary resources in the informer cache are related to.
27
-
- setting up multiple informers for the same type if needed (you need informer per namespace if the informer
28
-
is not watching the whole cluster)
29
-
- Dynamically adding/removing watched namespaces.
30
-
- Some others, what is out of the scope of this document.
25
+
However, `InformerEventSource` also provide additional capabilities such as:
31
26
32
-
### Associating Secondary Resources to Primary Resource
27
+
- recording the relations between primary and secondary resources so that the event source knows which primary resource
28
+
to trigger a reconciler with whenever one of the cached secondary resources cached by the informer changes,
29
+
- setting up multiple informers for the same type if needed, for example to transparently watch multiple namespaces,
30
+
without you having to worry about it,
31
+
- dynamically adding/removing watched namespaces, if needed
32
+
- and more, outside of the scope of this document.
33
33
34
-
The question is, how to trigger reconciliation of a primary resources (your custom resource),
35
-
when Informer receives a new resource.
36
-
For this purpose the framework uses [`SecondaryToPrimaryMapper`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/SecondaryToPrimaryMapper.java)
37
-
that tells (usually) based on the resource which primary resource reconciliation to trigger.
38
-
The mapping is usually done based on the owner reference or annotation on the secondary resource.
39
-
(But not always, as we will see)
34
+
### Associating Secondary Resources to Primary Resource
40
35
41
-
It is important to realize that if a resource triggers the reconciliation of a primary resource, that
42
-
resource naturally will be used during reconciliation. So the reconciler will need to access them.
43
-
Therefore, InformerEventSource maintains a reverse index [PrimaryToSecondaryIndex](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/DefaultPrimaryToSecondaryIndex.java),
44
-
based on the result of the `SecondaryToPrimaryMapper` result.
36
+
Event sources need to trigger the appropriate reconciler, providing the correct primary resource, whenever one of their
37
+
handled secondary resources changes. It is thus core to an event source's role to identify which primary resource (
38
+
usually, your custom resource) is potentially impacted by that change.
39
+
The framework uses [`SecondaryToPrimaryMapper`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/SecondaryToPrimaryMapper.java)
40
+
for this purpose. For `InformerEventSources`, which target Kubernetes resources, this mapping is typically done using
41
+
either the owner reference or an annotation on the secondary resource. For external resources, other mechanisms need to
42
+
be used and there are also cases where the default mechanisms provided by the SDK do not work, even for Kubernetes
43
+
resources.
44
+
45
+
However, once the event source has triggered a primary resource reconciliation, the associated reconciler needs to
46
+
access the secondary resources which changes caused the reconciliation. Indeed, the information from the secondary
47
+
resources might be needed during the reconciliation. For that purpose,
48
+
`InformerEventSource` maintains a reverse
49
+
index [PrimaryToSecondaryIndex](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/DefaultPrimaryToSecondaryIndex.java),
50
+
based on the result of the `SecondaryToPrimaryMapper`result.
45
51
46
52
## Unified API for Related Resources
47
53
48
-
To access all related resources for a primary resource, the framework provides an API to access the related
To access all related resources for a primary resource, the framework provides an API to access the related
55
+
secondary resources using the `Set<R> getSecondaryResources(Class<R> expectedType)` method of the `Context` object
56
+
provided as part of the `reconcile` method.
54
57
55
-
That will list all the related resources of a certain type, based on the `InformerEventSource`'s`PrimaryToSecondaryIndex`.
56
-
Based on that index, it reads the resources from the Informers cache. Note that since all those steps work
58
+
For `InformerEventSource`, this will leverage the associated`PrimaryToSecondaryIndex`. Resources are then retrieved
59
+
from the informer's cache. Note that since all those steps work
57
60
on top of indexes, those operations are very fast, usually O(1).
58
61
59
-
We mostly talk about InformerEventSource, but this works in similar ways for generalized EventSources concept, since
60
-
the [`EventSource`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSource.java#L93)
61
-
actually implements the `Set<R> getSecondaryResources(P primary);` method. That is just called from the context.
62
+
While we've focused mostly on `InformerEventSource`, this concept can be extended to all `EventSources`, since
@@ -95,25 +99,28 @@ public class WebPageReconciler implements Reconciler<WebPage> {
95
99
## The Use Case for PrimaryToSecondaryMapper
96
100
97
101
As we discussed, we provide a unified API to access related resources using `Context.getSecondaryResources(...)`.
98
-
This method was on purpose uses `Secondary` resource, since those are not only child resources - how
99
-
resources that are created by the reconciler are sometimes called in Kubernetes world - and usually have owner references for the custom resources;
100
-
neither related resources which are usually resources that serves as input for the primary (not managed).
101
-
It is the union of both.
102
-
103
-
The issue arises when we want to trigger reconciliation for a resource, that does not have an owner reference or other direct
104
-
association with the primary resource.
105
-
Typically, if you have ConfigMap where you have input parameters for a set of primary resources,
106
-
and the primary is actually referencing the secondary resource.
107
-
In other words, having the name of the ConfigMap in the spec part of the primary resource.
108
-
109
-
As an example we provide, have a primary resource a `Job` that references a `Cluster` resource.
110
-
So multiple `Job` can reference the same `Cluster`, and we want to trigger `Job` reconciliation if cluster changes.
111
-
See full sample [here](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/primarytosecondary).
112
-
But the `Cluster` (the secondary resource) does not reference the `Jobs`.
113
-
114
-
Even writing a `SecondaryToPrimaryMapper` is not trivial in this case, if the cluster is updated, we want to trigger
115
-
all `Jobs` that are referencing it. So we have to efficiently get the list of jobs, and return their ResourceIDs in
116
-
the mapper. So we need an index that maps `Cluster` to `Jobs`. Here we can use indexing capabilities of the Informers:
102
+
The name `Secondary` refers to resources that a reconciler needs to take into account to properly reconcile a primary
103
+
resource. These resources cover more than only `child` resources as resources created by a reconciler are sometimes
104
+
called and which usually have a owner reference pointing to the primary (and, typically, custom) resource. These also
105
+
cover `related` resources (which might or might not be managed by Kubernetes) that serve as input for reconciliations.
106
+
107
+
There are cases where the SDK needs more information than what is readily available, in particular when some of these
108
+
secondary resources do not have owner references or anything direct link to the primary resource they are associated
109
+
with.
110
+
111
+
As an example we provide, consider a `Job` primary resource which can be assigned to run on a cluster, represented by a
112
+
`Cluster` resource.
113
+
Multiple jobs can run on a given cluster so multiple `Job` resources can reference the same `Cluster` resource. However,
114
+
a `Cluster` resource should not know about `Job` resources as this information is not part of what a cluster *is*.
115
+
However, when a cluster changes, we might want to redirect the associated jobs to other clusters. Our reconciler
116
+
therefore needs to figure out which `Job` (primary) resources are associated with the changed `Cluster` (secondary)
0 commit comments