Skip to content

Commit 671f9bf

Browse files
metacosmcsviri
authored andcommitted
docs: add flow chart to motivation, detail design
1 parent b66fa9e commit 671f9bf

File tree

1 file changed

+101
-18
lines changed

1 file changed

+101
-18
lines changed
Lines changed: 101 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,118 @@
11
---
2-
title: Dependent Resources Feature
3-
description: Dependent Resources Feature
4-
layout: docs
5-
permalink: /docs/dependent-resources
2+
title: Dependent Resources Feature description: Dependent Resources Feature layout: docs permalink:
3+
/docs/dependent-resources
64
---
75

86
# Dependent Resources
97

10-
DISCLAIMER: Dependent Resources is relatively new and implementation wise not a simple concept, some APIs could be still
11-
a subject of change in the future. However, in case of non-backwards compatible change is expected to be trivial to
12-
migrate.
8+
DISCLAIMER: The Dependent Resource support is relatively new and, while we strove to cover what we
9+
anticipate will be the most common use cases, the implementation is not simple and might still
10+
evolve. As a result, some APIs could be still a subject of change in the future. However,
11+
non-backwards compatible changes are expected to be trivial to adapt to.
1312

1413
## Motivations and Goals
1514

16-
During a reconciliation controller is managing other "secondary" resources. Typically, the following steps are executed:
15+
Most operators need to deal with secondary resources when trying to realize the desired state
16+
described by the primary resource it is in charge of. For example, the Kubernetes-native
17+
`Deployment` controller needs to manage `ReplicaSet` instances as part of a `Deployment`'s
18+
reconciliation process. In this instance, `ReplicatSet` is considered a secondary resource for
19+
the `Deployment` controller.
1720

18-
1. Check if the desired resource already exists (usually if already present in the cache of an EventSource).
19-
2. If the resource not exists create one with the desired spec.
20-
3. If resource already exists, check if the spec of the resources is the same as desired.
21-
1. If the actual spec is different from the desired spec update it.
21+
Controllers that deal with secondary resources typically need to perform the following steps, for
22+
each secondary resource:
2223

23-
The process how the resource is read, created, updated or the desired state is compared to the actual state in
24-
Kubernetes API are all generic sub-problems in a reconciler implementation.
25-
The motivation behind Dependent Resource is hide the mentioned problems (and much
26-
more) from the developer and provide a system that allows managing the secondary resources in an
27-
elegant and structured way.
24+
```mermaid
25+
flowchart TD
26+
27+
A{Secondary resource exists?}
28+
A -- Yes --> match
29+
A -- No --> compute
30+
31+
compute[Compute desired state based on primary state] --> Create --> Done
32+
match{Matches desired state as defined by primary?}
33+
match -- Yes --> Done
34+
match -- No --> Update
35+
36+
```
37+
38+
As this process is pretty much similar for each dependent resource, it makes sense for the SDK to
39+
offer some level of support for these repetitive actions to remove the boilerplate code. While these
40+
steps are not difficult in and of themselves, there are some subtleties that can lead to bugs or
41+
sub-optimal code if not done right. It should be possible to handle common cases (such as dealing
42+
with Kubernetes-native secondary resources) in a semi-declarative way with only a minimal amount of
43+
code, JOSDK taking care of wiring everything accordingly.
44+
45+
Moreover, in order for your reconciler to get informed of events on these secondary resources, you
46+
need to configure and create event sources and maintain them. JOSDK already makes it rather easy to
47+
deal with these but we felt that we could make things even simpler.
48+
49+
Finally, there are also opportunities for the SDK to transparently add features that are even
50+
trickier to get right, such as immediate caching of updated or created resources (so that your
51+
reconciler doesn't need to wait for a cluster roundtrip to continue its work) and associated event
52+
filtering (so that something your reconciler just changed doesn't re-trigger a reconciliation, for
53+
example).
2854

2955
## Design
3056

57+
### `DependentResource` vs. `AbstractDependentResource`
58+
59+
The new `DependentResource` interface lies at the core of the design and strives to encapsulate the
60+
logic that is required to reconcile the state of the associated secondary resource based on the
61+
state of the primary one. For most cases, this logic will follow the flow expressed above and JOSDK
62+
provides a very convenient implementation of this logic in the form of the
63+
`AbstractDependentResource` class. If your logic doesn't fit this pattern, though, you can still
64+
provide your own `reconcile` method implementation. While the benefits of using dependent resources
65+
are less obvious in that case, this allows you to separate the logic necessary to deal with each
66+
secondary resource in its own class that can then be tested in isolation via unit tests. You can
67+
also use the declarative support with your own implementations as we shall see later on.
68+
69+
`AbstractDependentResource` is designed so that classes extending it specify which functionality
70+
they support by implementing trait interfaces. This design has been selected to express the fact
71+
that not all secondary resources are completely under the control of the primary reconciler: some
72+
dependent resources are only ever created or updated for example and we needed a way to let JOSDK
73+
when that is the case. We therefore provide trait interfaces: `Creator`,
74+
`Updater` and `Deleter` to express that the `DependentResource` implementation will provide custom
75+
functionality to create, update and delete its associated secondary resources, respectively. If
76+
these traits are not implemented then parts of the logic described above is never triggered: if your
77+
implementation doesn't implement `Creator`, for example,
78+
`AbstractDependentResource` will never try to create the associated secondary resource, even if it
79+
doesn't exist. It is thus possible to create read-only dependent resources that will trigger your
80+
reconciler whenever a user interacts with them but that are never modified by your reconciler
81+
itself.
82+
83+
### Batteries included: convenient `DependentResource` implementations!
84+
85+
JOSDK also offers several other convenient implementations building on top of
86+
`AbstractDependentResource` that you can use as starting points for your own implementations.
87+
88+
One such implementation is the `KubernetesDependentResource` class that makes it really easy to work
89+
with Kubernetes-native resources as, in this case, you usually only need to provide an
90+
implementation for the `desired` method to tell JOSDK what the desired state of your secondary
91+
resource should be based on the specified primary resource state. JOSDK takes care of everything
92+
else using default implementations that you can override in case you need more precise control of
93+
what's going on.
94+
95+
We also provide implementations that makes it very easy to cache
96+
(`AbstractCachingDependentResource`) or make it easy to poll for changes in external
97+
resources (`PollingDependentResource`, `PerResourcePollingDependentResource`).
98+
99+
FIX-ME: the following currently isn't true but we should put all in the same package hierarchy, see
100+
https://github.com/java-operator-sdk/java-operator-sdk/issues/1049
101+
All the provided implementations can be found in
102+
the `io/javaoperatorsdk/operator/processing/dependent` package.
103+
31104
## Managed Dependent Resources
32105

106+
As mentioned previously, one goal of this implementation is to make it possible to
107+
semi-declaratively create and wire dependent resources. You can annotate your reconciler with
108+
`@Dependent` annotations that specify which `DependentResource` implementation it depends upon and
109+
JOSDK will take the appropriate steps to wire everything thing together and call your
110+
`DependentResource` implementations `reconcile` method before your primary resource is reconciled.
111+
This makes sense in most use cases where the logic associated with the primary resource is usually
112+
limited to status handling based on the state of the secondary resources. This behavior and
113+
automated handling is referred to as "managed" because the `DependentResource`
114+
implementations are managed by JOSDK.
115+
33116
## Standalone Dependent Resources
34117

35-
## Other Problems Handled by Dependent Resources
118+
## Other Dependent Resources features

0 commit comments

Comments
 (0)