Skip to content

Commit e74d928

Browse files
committed
docs: add Matcher information, show how to use metadata matching
1 parent 6ad6eea commit e74d928

File tree

1 file changed

+109
-80
lines changed

1 file changed

+109
-80
lines changed

docs/documentation/dependent-resources.md

Lines changed: 109 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,35 @@ possible to not implement any of these traits and therefore create read-only dep
8686
that will trigger your reconciler whenever a user interacts with them but that are never
8787
modified by your reconciler itself.
8888

89+
[`AbstractSimpleDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractSimpleDependentResource.java)
90+
and [`KubernetesDependentResource`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java)
91+
sub-classes can also implement
92+
the [`Matcher`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/Matcher.java)
93+
interface to customize how the SDK decides whether or not the actual state of the dependent
94+
matches the desired state. This makes it convenient to use these abstract base classes for your
95+
implementation, only customizing the matching logic. Note that in many cases, there is no need
96+
to customize that logic as the SDK already provides convenient default implementations in the
97+
form
98+
of [`DesiredEqualsMatcher`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DesiredEqualsMatcher.java)
99+
and
100+
[`GenericKubernetesResourceMatcher`](https://github.com/java-operator-sdk/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java)
101+
implementations, respectively. If you want to provide custom logic, you only need your
102+
`DependentResource` implementation to implement the `Matcher` interface as below, which shows
103+
how to customize the default matching logic for Kubernetes resource to also consider annotations
104+
and labels, which are ignored by default:
105+
106+
```java
107+
public class MyDependentResource extends KubernetesDependentResource<MyDependent, MyPrimary>
108+
implements Matcher<MyDependent, MyPrimary> {
109+
// your implementation
110+
111+
public Result<MyDependent> match(MyDependent actualResource, MyPrimary primary,
112+
Context<MyPrimary> context) {
113+
return GenericKubernetesResourceMatcher.match(this, actualResource, primary, context, true);
114+
}
115+
}
116+
```
117+
89118
### Batteries included: convenient DependentResource implementations!
90119

91120
JOSDK also offers several other convenient implementations building on top of
@@ -116,7 +145,7 @@ Deleted (or set to be garbage collected). The following example shows how to cre
116145
@KubernetesDependent(labelSelector = WebPageManagedDependentsReconciler.SELECTOR)
117146
class DeploymentDependentResource extends CRUDKubernetesDependentResource<Deployment, WebPage> {
118147

119-
public DeploymentDependentResource() {
148+
public DeploymentDependentResource() {
120149
super(Deployment.class);
121150
}
122151

@@ -169,26 +198,26 @@ instances are managed by JOSDK, an example of which can be seen below:
169198
```java
170199

171200
@ControllerConfiguration(
172-
labelSelector = SELECTOR,
173-
dependents = {
174-
@Dependent(type = ConfigMapDependentResource.class),
175-
@Dependent(type = DeploymentDependentResource.class),
176-
@Dependent(type = ServiceDependentResource.class)
177-
})
201+
labelSelector = SELECTOR,
202+
dependents = {
203+
@Dependent(type = ConfigMapDependentResource.class),
204+
@Dependent(type = DeploymentDependentResource.class),
205+
@Dependent(type = ServiceDependentResource.class)
206+
})
178207
public class WebPageManagedDependentsReconciler
179-
implements Reconciler<WebPage>, ErrorStatusHandler<WebPage> {
208+
implements Reconciler<WebPage>, ErrorStatusHandler<WebPage> {
180209

181-
// omitted code
210+
// omitted code
182211

183-
@Override
184-
public UpdateControl<WebPage> reconcile(WebPage webPage, Context<WebPage> context)
185-
throws Exception {
212+
@Override
213+
public UpdateControl<WebPage> reconcile(WebPage webPage, Context<WebPage> context)
214+
throws Exception {
186215

187-
final var name = context.getSecondaryResource(ConfigMap.class).orElseThrow()
188-
.getMetadata().getName();
189-
webPage.setStatus(createStatus(name));
190-
return UpdateControl.patchStatus(webPage);
191-
}
216+
final var name = context.getSecondaryResource(ConfigMap.class).orElseThrow()
217+
.getMetadata().getName();
218+
webPage.setStatus(createStatus(name));
219+
return UpdateControl.patchStatus(webPage);
220+
}
192221

193222
}
194223
```
@@ -215,69 +244,69 @@ an `Ingress`:
215244

216245
@ControllerConfiguration
217246
public class WebPageStandaloneDependentsReconciler
218-
implements Reconciler<WebPage>, ErrorStatusHandler<WebPage>,
219-
EventSourceInitializer<WebPage> {
220-
221-
private KubernetesDependentResource<ConfigMap, WebPage> configMapDR;
222-
private KubernetesDependentResource<Deployment, WebPage> deploymentDR;
223-
private KubernetesDependentResource<Service, WebPage> serviceDR;
224-
private KubernetesDependentResource<Service, WebPage> ingressDR;
225-
226-
public WebPageStandaloneDependentsReconciler(KubernetesClient kubernetesClient) {
227-
// 1.
228-
createDependentResources(kubernetesClient);
229-
}
230-
231-
@Override
232-
public List<EventSource> prepareEventSources(EventSourceContext<WebPage> context) {
233-
// 2.
234-
return List.of(
235-
configMapDR.initEventSource(context),
236-
deploymentDR.initEventSource(context),
237-
serviceDR.initEventSource(context));
238-
}
239-
240-
@Override
241-
public UpdateControl<WebPage> reconcile(WebPage webPage, Context<WebPage> context)
242-
throws Exception {
243-
244-
// 3.
245-
if (!isValidHtml(webPage.getHtml())) {
246-
return UpdateControl.patchStatus(setInvalidHtmlErrorMessage(webPage));
247-
}
248-
249-
// 4.
250-
configMapDR.reconcile(webPage, context);
251-
deploymentDR.reconcile(webPage, context);
252-
serviceDR.reconcile(webPage, context);
253-
254-
// 5.
255-
if (Boolean.TRUE.equals(webPage.getSpec().getExposed())) {
256-
ingressDR.reconcile(webPage, context);
257-
} else {
258-
ingressDR.delete(webPage, context);
259-
}
260-
261-
// 6.
262-
webPage.setStatus(
263-
createStatus(configMapDR.getResource(webPage).orElseThrow().getMetadata().getName()));
264-
return UpdateControl.patchStatus(webPage);
265-
}
266-
267-
private void createDependentResources(KubernetesClient client) {
268-
this.configMapDR = new ConfigMapDependentResource();
269-
this.deploymentDR = new DeploymentDependentResource();
270-
this.serviceDR = new ServiceDependentResource();
271-
this.ingressDR = new IngressDependentResource();
272-
273-
Arrays.asList(configMapDR, deploymentDR, serviceDR, ingressDR).forEach(dr -> {
274-
dr.setKubernetesClient(client);
275-
dr.configureWith(new KubernetesDependentResourceConfig()
276-
.setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR));
277-
});
278-
}
279-
280-
// omitted code
247+
implements Reconciler<WebPage>, ErrorStatusHandler<WebPage>,
248+
EventSourceInitializer<WebPage> {
249+
250+
private KubernetesDependentResource<ConfigMap, WebPage> configMapDR;
251+
private KubernetesDependentResource<Deployment, WebPage> deploymentDR;
252+
private KubernetesDependentResource<Service, WebPage> serviceDR;
253+
private KubernetesDependentResource<Service, WebPage> ingressDR;
254+
255+
public WebPageStandaloneDependentsReconciler(KubernetesClient kubernetesClient) {
256+
// 1.
257+
createDependentResources(kubernetesClient);
258+
}
259+
260+
@Override
261+
public List<EventSource> prepareEventSources(EventSourceContext<WebPage> context) {
262+
// 2.
263+
return List.of(
264+
configMapDR.initEventSource(context),
265+
deploymentDR.initEventSource(context),
266+
serviceDR.initEventSource(context));
267+
}
268+
269+
@Override
270+
public UpdateControl<WebPage> reconcile(WebPage webPage, Context<WebPage> context)
271+
throws Exception {
272+
273+
// 3.
274+
if (!isValidHtml(webPage.getHtml())) {
275+
return UpdateControl.patchStatus(setInvalidHtmlErrorMessage(webPage));
276+
}
277+
278+
// 4.
279+
configMapDR.reconcile(webPage, context);
280+
deploymentDR.reconcile(webPage, context);
281+
serviceDR.reconcile(webPage, context);
282+
283+
// 5.
284+
if (Boolean.TRUE.equals(webPage.getSpec().getExposed())) {
285+
ingressDR.reconcile(webPage, context);
286+
} else {
287+
ingressDR.delete(webPage, context);
288+
}
289+
290+
// 6.
291+
webPage.setStatus(
292+
createStatus(configMapDR.getResource(webPage).orElseThrow().getMetadata().getName()));
293+
return UpdateControl.patchStatus(webPage);
294+
}
295+
296+
private void createDependentResources(KubernetesClient client) {
297+
this.configMapDR = new ConfigMapDependentResource();
298+
this.deploymentDR = new DeploymentDependentResource();
299+
this.serviceDR = new ServiceDependentResource();
300+
this.ingressDR = new IngressDependentResource();
301+
302+
Arrays.asList(configMapDR, deploymentDR, serviceDR, ingressDR).forEach(dr -> {
303+
dr.setKubernetesClient(client);
304+
dr.configureWith(new KubernetesDependentResourceConfig()
305+
.setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR));
306+
});
307+
}
308+
309+
// omitted code
281310
}
282311
```
283312

0 commit comments

Comments
 (0)