Skip to content

Commit da84de0

Browse files
committed
docs: migrate v5 changes to docsy (#2397)
Signed-off-by: Attila Mészáros <[email protected]>
1 parent 2a4cfcc commit da84de0

File tree

4 files changed

+249
-271
lines changed

4 files changed

+249
-271
lines changed

docsy/content/en/docs/dependent-resources/_index.md

+84-167
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ title: Dependent Resources
33
weight: 60
44
---
55

6+
# Dependent Resources
7+
68
## Motivations and Goals
79

810
Most operators need to deal with secondary resources when trying to realize the desired state
@@ -97,13 +99,13 @@ and labels, which are ignored by default:
9799

98100
```java
99101
public class MyDependentResource extends KubernetesDependentResource<MyDependent, MyPrimary>
100-
implements Matcher<MyDependent, MyPrimary> {
101-
// your implementation
102+
implements Matcher<MyDependent, MyPrimary> {
103+
// your implementation
102104

103-
public Result<MyDependent> match(MyDependent actualResource, MyPrimary primary,
104-
Context<MyPrimary> context) {
105-
return GenericKubernetesResourceMatcher.match(this, actualResource, primary, context, true);
106-
}
105+
public Result<MyDependent> match(MyDependent actualResource, MyPrimary primary,
106+
Context<MyPrimary> context) {
107+
return GenericKubernetesResourceMatcher.match(this, actualResource, primary, context, true);
108+
}
107109
}
108110
```
109111

@@ -137,24 +139,24 @@ Deleted (or set to be garbage collected). The following example shows how to cre
137139
@KubernetesDependent(labelSelector = WebPageManagedDependentsReconciler.SELECTOR)
138140
class DeploymentDependentResource extends CRUDKubernetesDependentResource<Deployment, WebPage> {
139141

140-
public DeploymentDependentResource() {
141-
super(Deployment.class);
142-
}
143-
144-
@Override
145-
protected Deployment desired(WebPage webPage, Context<WebPage> context) {
146-
var deploymentName = deploymentName(webPage);
147-
Deployment deployment = loadYaml(Deployment.class, getClass(), "deployment.yaml");
148-
deployment.getMetadata().setName(deploymentName);
149-
deployment.getMetadata().setNamespace(webPage.getMetadata().getNamespace());
150-
deployment.getSpec().getSelector().getMatchLabels().put("app", deploymentName);
151-
152-
deployment.getSpec().getTemplate().getMetadata().getLabels()
153-
.put("app", deploymentName);
154-
deployment.getSpec().getTemplate().getSpec().getVolumes().get(0)
155-
.setConfigMap(new ConfigMapVolumeSourceBuilder().withName(configMapName(webPage)).build());
156-
return deployment;
157-
}
142+
public DeploymentDependentResource() {
143+
super(Deployment.class);
144+
}
145+
146+
@Override
147+
protected Deployment desired(WebPage webPage, Context<WebPage> context) {
148+
var deploymentName = deploymentName(webPage);
149+
Deployment deployment = loadYaml(Deployment.class, getClass(), "deployment.yaml");
150+
deployment.getMetadata().setName(deploymentName);
151+
deployment.getMetadata().setNamespace(webPage.getMetadata().getNamespace());
152+
deployment.getSpec().getSelector().getMatchLabels().put("app", deploymentName);
153+
154+
deployment.getSpec().getTemplate().getMetadata().getLabels()
155+
.put("app", deploymentName);
156+
deployment.getSpec().getTemplate().getSpec().getVolumes().get(0)
157+
.setConfigMap(new ConfigMapVolumeSourceBuilder().withName(configMapName(webPage)).build());
158+
return deployment;
159+
}
158160
}
159161
```
160162

@@ -190,25 +192,25 @@ instances are managed by JOSDK, an example of which can be seen below:
190192
```java
191193

192194
@ControllerConfiguration(
193-
labelSelector = SELECTOR,
194-
dependents = {
195-
@Dependent(type = ConfigMapDependentResource.class),
196-
@Dependent(type = DeploymentDependentResource.class),
197-
@Dependent(type = ServiceDependentResource.class)
198-
})
195+
labelSelector = SELECTOR,
196+
dependents = {
197+
@Dependent(type = ConfigMapDependentResource.class),
198+
@Dependent(type = DeploymentDependentResource.class),
199+
@Dependent(type = ServiceDependentResource.class)
200+
})
199201
public class WebPageManagedDependentsReconciler
200-
implements Reconciler<WebPage>, ErrorStatusHandler<WebPage> {
202+
implements Reconciler<WebPage>, ErrorStatusHandler<WebPage> {
201203

202-
// omitted code
204+
// omitted code
203205

204-
@Override
205-
public UpdateControl<WebPage> reconcile(WebPage webPage, Context<WebPage> context) {
206+
@Override
207+
public UpdateControl<WebPage> reconcile(WebPage webPage, Context<WebPage> context) {
206208

207-
final var name = context.getSecondaryResource(ConfigMap.class).orElseThrow()
208-
.getMetadata().getName();
209-
webPage.setStatus(createStatus(name));
210-
return UpdateControl.patchStatus(webPage);
211-
}
209+
final var name = context.getSecondaryResource(ConfigMap.class).orElseThrow()
210+
.getMetadata().getName();
211+
webPage.setStatus(createStatus(name));
212+
return UpdateControl.patchStatus(webPage);
213+
}
212214

213215
}
214216
```
@@ -223,104 +225,11 @@ It is also possible to wire dependent resources programmatically. In practice th
223225
developer is responsible for initializing and managing the dependent resources as well as calling
224226
their `reconcile` method. However, this makes it possible for developers to fully customize the
225227
reconciliation process. Standalone dependent resources should be used in cases when the managed use
226-
case does not fit.
227-
228-
Note that [Workflows](https://javaoperatorsdk.io/docs/workflows) also can be invoked from standalone
229-
resources.
230-
231-
The following sample is similar to the one above, simply performing additional checks, and
232-
conditionally creating an `Ingress`:
233-
234-
```java
235-
236-
@ControllerConfiguration
237-
public class WebPageStandaloneDependentsReconciler
238-
implements Reconciler<WebPage>, ErrorStatusHandler<WebPage>,
239-
EventSourceInitializer<WebPage> {
240-
241-
private KubernetesDependentResource<ConfigMap, WebPage> configMapDR;
242-
private KubernetesDependentResource<Deployment, WebPage> deploymentDR;
243-
private KubernetesDependentResource<Service, WebPage> serviceDR;
244-
private KubernetesDependentResource<Service, WebPage> ingressDR;
245-
246-
public WebPageStandaloneDependentsReconciler(KubernetesClient kubernetesClient) {
247-
// 1.
248-
createDependentResources(kubernetesClient);
249-
}
250-
251-
@Override
252-
public List<EventSource> prepareEventSources(EventSourceContext<WebPage> context) {
253-
// 2.
254-
return List.of(
255-
configMapDR.initEventSource(context),
256-
deploymentDR.initEventSource(context),
257-
serviceDR.initEventSource(context));
258-
}
259-
260-
@Override
261-
public UpdateControl<WebPage> reconcile(WebPage webPage, Context<WebPage> context) {
262-
263-
// 3.
264-
if (!isValidHtml(webPage.getHtml())) {
265-
return UpdateControl.patchStatus(setInvalidHtmlErrorMessage(webPage));
266-
}
267-
268-
// 4.
269-
configMapDR.reconcile(webPage, context);
270-
deploymentDR.reconcile(webPage, context);
271-
serviceDR.reconcile(webPage, context);
272-
273-
// 5.
274-
if (Boolean.TRUE.equals(webPage.getSpec().getExposed())) {
275-
ingressDR.reconcile(webPage, context);
276-
} else {
277-
ingressDR.delete(webPage, context);
278-
}
228+
case does not fit. You can, of course, also use [Workflows](https://javaoperatorsdk.io/docs/workflows) when managing
229+
resources programmatically.
279230

280-
// 6.
281-
webPage.setStatus(
282-
createStatus(configMapDR.getResource(webPage).orElseThrow().getMetadata().getName()));
283-
return UpdateControl.patchStatus(webPage);
284-
}
285-
286-
private void createDependentResources(KubernetesClient client) {
287-
this.configMapDR = new ConfigMapDependentResource();
288-
this.deploymentDR = new DeploymentDependentResource();
289-
this.serviceDR = new ServiceDependentResource();
290-
this.ingressDR = new IngressDependentResource();
291-
292-
Arrays.asList(configMapDR, deploymentDR, serviceDR, ingressDR).forEach(dr -> {
293-
dr.setKubernetesClient(client);
294-
dr.configureWith(new KubernetesDependentResourceConfig()
295-
.setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR));
296-
});
297-
}
298-
299-
// omitted code
300-
}
301-
```
302-
303-
There are multiple things happening here:
304-
305-
1. Dependent resources are explicitly created and can be access later by reference.
306-
2. Event sources are produced by the dependent resources, but needs to be explicitly registered in
307-
this case by implementing
308-
the [`EventSourceInitializer`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceInitializer.java)
309-
interface.
310-
3. The input html is validated, and error message is set in case it is invalid.
311-
4. Reconciliation of dependent resources is called explicitly, but here the workflow
312-
customization is fully in the hand of the developer.
313-
5. An `Ingress` is created but only in case `exposed` flag set to true on custom resource. Tries to
314-
delete it if not.
315-
6. Status is set in a different way, this is just an alternative way to show, that the actual state
316-
can be read using the reference. This could be written in a same way as in the managed example.
317-
318-
See the full source code of
319-
sample [here](https://github.com/operator-framework/java-operator-sdk/blob/main/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java)
320-
.
321-
322-
Note also the Workflows feature makes it possible to also support this conditional creation use
323-
case in managed dependent resources.
231+
You can see a commented example of how to do
232+
so [here](https://github.com/operator-framework/java-operator-sdk/blob/main/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageStandaloneDependentsReconciler.java).
324233

325234
## Creating/Updating Kubernetes Resources
326235

@@ -353,17 +262,17 @@ Since SSA is a complex feature, JOSDK implements a feature flag allowing users t
353262
these implementations. See
354263
in [ConfigurationService](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java#L332-L358).
355264

356-
It is, however, important to note that these implementations are default, generic
357-
implementations that the framework can provide expected behavior out of the box. In many
358-
situations, these will work just fine but it is also possible to provide matching algorithms
265+
It is, however, important to note that these implementations are default, generic
266+
implementations that the framework can provide expected behavior out of the box. In many
267+
situations, these will work just fine but it is also possible to provide matching algorithms
359268
optimized for specific use cases. This is easily done by simply overriding
360-
the `match(...)` [method](https://github.com/java-operator-sdk/java-operator-sdk/blob/e16559fd41bbb8bef6ce9d1f47bffa212a941b09/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java#L156-L156).
269+
the `match(...)` [method](https://github.com/java-operator-sdk/java-operator-sdk/blob/e16559fd41bbb8bef6ce9d1f47bffa212a941b09/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java#L156-L156).
361270

362-
It is also possible to bypass the matching logic altogether to simply rely on the server-side
271+
It is also possible to bypass the matching logic altogether to simply rely on the server-side
363272
apply mechanism if always sending potentially unchanged resources to the cluster is not an issue.
364273
JOSDK's matching mechanism allows to spare some potentially useless calls to the Kubernetes API
365-
server. To bypass the matching feature completely, simply override the `match` method to always
366-
return `false`, thus telling JOSDK that the actual state never matches the desired one, making
274+
server. To bypass the matching feature completely, simply override the `match` method to always
275+
return `false`, thus telling JOSDK that the actual state never matches the desired one, making
367276
it always update the resources using SSA.
368277

369278
WARNING: Older versions of Kubernetes before 1.25 would create an additional resource version for every SSA update
@@ -390,20 +299,25 @@ tests [here](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/op
390299

391300
When dealing with multiple dependent resources of same type, the dependent resource implementation
392301
needs to know which specific resource should be targeted when reconciling a given dependent
393-
resource, since there will be multiple instances of that type which could possibly be used, each
394-
associated with the same primary resource. In order to do this, JOSDK relies on the
395-
[resource discriminator](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceDiscriminator.java)
396-
concept. Resource discriminators uniquely identify the target resource of a dependent resource.
397-
In the managed Kubernetes dependent resources case, the discriminator can be declaratively set
398-
using the `@KubernetesDependent` annotation:
399-
400-
```java
401-
402-
@KubernetesDependent(resourceDiscriminator = ConfigMap1Discriminator.class)
403-
public class MultipleManagedDependentResourceConfigMap1 {
404-
//...
405-
}
406-
```
302+
resource, since there could be multiple instances of that type which could possibly be used, each
303+
associated with the same primary resource. In this situation, JOSDK automatically selects the appropriate secondary
304+
resource matching the desired state associated with the primary resource. This makes sense because the desired
305+
state computation already needs to be able to discriminate among multiple related secondary resources to tell JOSDK how
306+
they should be reconciled.
307+
308+
There might be casees, though, where it might be problematic to call the `desired` method several times (for example, because it is costly to do so), it is always possible to override this automated discrimination using several means:
309+
310+
- Implement your own `getSecondaryResource` method on your `DependentResource` implementation from scratch.
311+
- Override the `selectManagedSecondaryResource` method, if your `DependentResource` extends `AbstractDependentResource`.
312+
This should be relatively simple to override this method to optimize the matching to your needs. You can see an
313+
example of such an implementation in
314+
the [`ExternalWithStateDependentResource`](https://github.com/operator-framework/java-operator-sdk/blob/6cd0f884a7c9b60c81bd2d52da54adbd64d6e118/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/externalstate/ExternalWithStateDependentResource.java#L43-L49)
315+
class.
316+
- Override the `managedSecondaryResourceID` method, if your `DependentResource` extends `KubernetesDependentResource`,
317+
where it's very often possible to easily determine the `ResourceID` of the secondary resource. This would probably be
318+
the easiest solution if you're working with Kubernetes resources.
319+
320+
### Sharing an Event Source Between Dependent Resources
407321

408322
Dependent resources usually also provide event sources. When dealing with multiple dependents of
409323
the same type, one needs to decide whether these dependent resources should track the same
@@ -419,10 +333,10 @@ would look as follows:
419333
useEventSourceWithName = "configMapSource")
420334
```
421335

422-
A sample is provided as an integration test both
423-
for [managed](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleManagedDependentSameTypeIT.java)
424-
and
425-
for [standalone](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleDependentResourceIT.java)
336+
A sample is provided as an integration test both:
337+
for [managed](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleManagedDependentNoDiscriminatorIT.java)
338+
339+
For [standalone](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleDependentResourceIT.java)
426340
cases.
427341

428342
## Bulk Dependent Resources
@@ -485,15 +399,18 @@ also be created, one per dependent resource.
485399
See [integration test](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/ExternalStateBulkIT.java)
486400
as a sample.
487401

488-
489402
## GenericKubernetesResource based Dependent Resources
490403

491-
In rare circumstances resource handling where there is no class representation or just typeless handling might be needed.
492-
Fabric8 Client provides [GenericKubernetesResource](https://github.com/fabric8io/kubernetes-client/blob/main/doc/CHEATSHEET.md#resource-typeless-api)
493-
to support that.
404+
In rare circumstances resource handling where there is no class representation or just typeless handling might be
405+
needed.
406+
Fabric8 Client
407+
provides [GenericKubernetesResource](https://github.com/fabric8io/kubernetes-client/blob/main/doc/CHEATSHEET.md#resource-typeless-api)
408+
to support that.
494409

495-
For dependent resource this is supported by [GenericKubernetesDependentResource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesDependentResource.java#L8-L8)
496-
. See samples [here](https://github.com/java-operator-sdk/java-operator-sdk/tree/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource).
410+
For dependent resource this is supported
411+
by [GenericKubernetesDependentResource](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesDependentResource.java#L8-L8)
412+
. See
413+
samples [here](https://github.com/java-operator-sdk/java-operator-sdk/tree/main/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/generickubernetesresource).
497414

498415
## Other Dependent Resource Features
499416

0 commit comments

Comments
 (0)