Skip to content

Commit 92ec192

Browse files
committed
feat: comparable resource version utils
1 parent 1f6560c commit 92ec192

File tree

42 files changed

+253
-132
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+253
-132
lines changed

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ public <P extends HasMetadata> RegisteredController<P> register(
258258
"Cannot register reconciler with name "
259259
+ reconciler.getClass().getCanonicalName()
260260
+ " reconciler named "
261-
+ ReconcilerUtils.getNameFor(reconciler)
261+
+ ReconcilerUtilsInternal.getNameFor(reconciler)
262262
+ " because its configuration cannot be found.\n"
263263
+ " Known reconcilers are: "
264264
+ configurationService.getKnownReconcilerNames());

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtils.java renamed to operator-framework-core/src/main/java/io/javaoperatorsdk/operator/ReconcilerUtilsInternal.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
3535

3636
@SuppressWarnings("rawtypes")
37-
public class ReconcilerUtils {
37+
public class ReconcilerUtilsInternal {
3838

3939
private static final String FINALIZER_NAME_SUFFIX = "/finalizer";
4040
protected static final String MISSING_GROUP_SUFFIX = ".javaoperatorsdk.io";
@@ -46,7 +46,7 @@ public class ReconcilerUtils {
4646
Pattern.compile(".*http(s?)://[^/]*/api(s?)/(\\S*).*"); // NOSONAR: input is controlled
4747

4848
// prevent instantiation of util class
49-
private ReconcilerUtils() {}
49+
private ReconcilerUtilsInternal() {}
5050

5151
public static boolean isFinalizerValid(String finalizer) {
5252
return HasMetadata.validateFinalizer(finalizer);

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/AbstractConfigurationService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
import io.fabric8.kubernetes.api.model.HasMetadata;
2424
import io.fabric8.kubernetes.client.KubernetesClient;
25-
import io.javaoperatorsdk.operator.ReconcilerUtils;
25+
import io.javaoperatorsdk.operator.ReconcilerUtilsInternal;
2626
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
2727

2828
/**
@@ -145,7 +145,7 @@ private String getReconcilersNameMessage() {
145145
}
146146

147147
protected <R extends HasMetadata> String keyFor(Reconciler<R> reconciler) {
148-
return ReconcilerUtils.getNameFor(reconciler);
148+
return ReconcilerUtilsInternal.getNameFor(reconciler);
149149
}
150150

151151
@SuppressWarnings("unused")

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/BaseConfigurationService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828

2929
import io.fabric8.kubernetes.api.model.HasMetadata;
3030
import io.fabric8.kubernetes.client.KubernetesClient;
31-
import io.javaoperatorsdk.operator.ReconcilerUtils;
31+
import io.javaoperatorsdk.operator.ReconcilerUtilsInternal;
3232
import io.javaoperatorsdk.operator.api.config.Utils.Configurator;
3333
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfigurationResolver;
3434
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
@@ -265,7 +265,7 @@ private <P extends HasMetadata> ResolvedControllerConfiguration<P> controllerCon
265265
io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration annotation) {
266266
final var resourceClass = getResourceClassResolver().getPrimaryResourceClass(reconcilerClass);
267267

268-
final var name = ReconcilerUtils.getNameFor(reconcilerClass);
268+
final var name = ReconcilerUtilsInternal.getNameFor(reconcilerClass);
269269
final var generationAware =
270270
valueOrDefaultFromAnnotation(
271271
annotation,

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import java.util.Set;
2121

2222
import io.fabric8.kubernetes.api.model.HasMetadata;
23-
import io.javaoperatorsdk.operator.ReconcilerUtils;
23+
import io.javaoperatorsdk.operator.ReconcilerUtilsInternal;
2424
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
2525
import io.javaoperatorsdk.operator.api.config.workflow.WorkflowSpec;
2626
import io.javaoperatorsdk.operator.api.reconciler.MaxReconciliationInterval;
@@ -42,16 +42,18 @@ default String getName() {
4242
}
4343

4444
default String getFinalizerName() {
45-
return ReconcilerUtils.getDefaultFinalizerName(getResourceClass());
45+
return ReconcilerUtilsInternal.getDefaultFinalizerName(getResourceClass());
4646
}
4747

4848
static String ensureValidName(String name, String reconcilerClassName) {
49-
return name != null ? name : ReconcilerUtils.getDefaultReconcilerName(reconcilerClassName);
49+
return name != null
50+
? name
51+
: ReconcilerUtilsInternal.getDefaultReconcilerName(reconcilerClassName);
5052
}
5153

5254
static String ensureValidFinalizerName(String finalizer, String resourceTypeName) {
5355
if (finalizer != null && !finalizer.isBlank()) {
54-
if (ReconcilerUtils.isFinalizerValid(finalizer)) {
56+
if (ReconcilerUtilsInternal.isFinalizerValid(finalizer)) {
5557
return finalizer;
5658
} else {
5759
throw new IllegalArgumentException(
@@ -61,7 +63,7 @@ static String ensureValidFinalizerName(String finalizer, String resourceTypeName
6163
+ " for details");
6264
}
6365
} else {
64-
return ReconcilerUtils.getDefaultFinalizerName(resourceTypeName);
66+
return ReconcilerUtilsInternal.getDefaultFinalizerName(resourceTypeName);
6567
}
6668
}
6769

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
import io.fabric8.kubernetes.api.model.HasMetadata;
2626
import io.fabric8.kubernetes.client.informers.cache.ItemStore;
2727
import io.javaoperatorsdk.operator.OperatorException;
28-
import io.javaoperatorsdk.operator.ReconcilerUtils;
28+
import io.javaoperatorsdk.operator.ReconcilerUtilsInternal;
2929
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
3030
import io.javaoperatorsdk.operator.api.config.Utils;
3131
import io.javaoperatorsdk.operator.api.reconciler.Constants;
@@ -92,7 +92,7 @@ private InformerConfiguration(Class<R> resourceClass) {
9292
// controller
9393
// where GenericKubernetesResource now does not apply
9494
? GenericKubernetesResource.class.getSimpleName()
95-
: ReconcilerUtils.getResourceTypeName(resourceClass);
95+
: ReconcilerUtilsInternal.getResourceTypeName(resourceClass);
9696
}
9797

9898
@SuppressWarnings({"rawtypes", "unchecked"})
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package io.javaoperatorsdk.operator.api.reconciler;
2+
3+
import java.util.function.UnaryOperator;
4+
5+
import io.fabric8.kubernetes.api.model.HasMetadata;
6+
import io.fabric8.kubernetes.client.dsl.base.PatchContext;
7+
import io.fabric8.kubernetes.client.dsl.base.PatchType;
8+
import io.javaoperatorsdk.operator.processing.event.source.informer.ManagedInformerEventSource;
9+
10+
public class ReconcilerUtils {
11+
// toto namespace handling
12+
// todo compare resource version if multiple event sources provide the same resource
13+
// for json patch make sense to retry (json merge patch?)
14+
15+
public static <R extends HasMetadata> R ssa(Context<? extends HasMetadata> context, R resource) {
16+
return handleResourcePatch(
17+
context,
18+
resource,
19+
r ->
20+
context
21+
.getClient()
22+
.resource(r)
23+
.patch(
24+
new PatchContext.Builder()
25+
.withForce(true)
26+
.withFieldManager(context.getControllerConfiguration().fieldManager())
27+
.withPatchType(PatchType.SERVER_SIDE_APPLY)
28+
.build()));
29+
}
30+
31+
public static <R extends HasMetadata> R ssaStatus(
32+
Context<? extends HasMetadata> context, R resource) {
33+
return handleResourcePatch(
34+
context,
35+
resource,
36+
r ->
37+
context
38+
.getClient()
39+
.resource(r)
40+
.subresource("status")
41+
.patch(
42+
new PatchContext.Builder()
43+
.withForce(true)
44+
.withFieldManager(context.getControllerConfiguration().fieldManager())
45+
.withPatchType(PatchType.SERVER_SIDE_APPLY)
46+
.build()));
47+
}
48+
49+
public static <P extends HasMetadata> P ssaPrimary(Context<P> context, P resource) {
50+
return handleResourcePatch(
51+
resource,
52+
r ->
53+
context
54+
.getClient()
55+
.resource(r)
56+
.patch(
57+
new PatchContext.Builder()
58+
.withForce(true)
59+
.withFieldManager(context.getControllerConfiguration().fieldManager())
60+
.withPatchType(PatchType.SERVER_SIDE_APPLY)
61+
.build()),
62+
true,
63+
context.eventSourceRetriever().getControllerEventSource());
64+
}
65+
66+
public static <P extends HasMetadata> P ssaStatusPrimary(Context<P> context, P resource) {
67+
return handleResourcePatch(
68+
resource,
69+
r ->
70+
context
71+
.getClient()
72+
.resource(r)
73+
.subresource("status")
74+
.patch(
75+
new PatchContext.Builder()
76+
.withForce(true)
77+
.withFieldManager(context.getControllerConfiguration().fieldManager())
78+
.withPatchType(PatchType.SERVER_SIDE_APPLY)
79+
.build()),
80+
true,
81+
context.eventSourceRetriever().getControllerEventSource());
82+
}
83+
84+
public static <R extends HasMetadata> R handleResourcePatch(
85+
Context<?> context, R resource, UnaryOperator<R> updateOperation) {
86+
var esList = context.eventSourceRetriever().getEventSourcesFor(resource.getClass());
87+
if (esList.isEmpty()) {
88+
throw new IllegalStateException("No event source found for type: " + resource.getClass());
89+
}
90+
if (esList.size() > 1) {
91+
throw new IllegalStateException(
92+
"Multiple event sources found for: "
93+
+ resource.getClass()
94+
+ " please provide the target event source");
95+
}
96+
var es = esList.get(0);
97+
if (es instanceof ManagedInformerEventSource mes) {
98+
return handleResourcePatch(resource, updateOperation, true, mes);
99+
} else {
100+
throw new IllegalStateException(
101+
"Target event source must be a subclass off "
102+
+ ManagedInformerEventSource.class.getName());
103+
}
104+
}
105+
106+
@SuppressWarnings("unchecked")
107+
private static <R extends HasMetadata> R handleResourcePatch(
108+
R resource,
109+
UnaryOperator<R> updateOperation,
110+
boolean doNotLock,
111+
ManagedInformerEventSource ies) {
112+
var resourceVersion = resource.getMetadata().getResourceVersion();
113+
try {
114+
if (resourceVersion != null && doNotLock) {
115+
resource.getMetadata().setResourceVersion(null);
116+
}
117+
return (R) ies.updateAndCacheResource(resource, updateOperation);
118+
} finally {
119+
if (resourceVersion != null && doNotLock) {
120+
resource.getMetadata().setResourceVersion(resourceVersion);
121+
}
122+
}
123+
}
124+
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ protected R handleCreate(R desired, P primary, Context<P> context) {
7777
.orElseThrow()
7878
.updateAndCacheResource(
7979
desired,
80-
context,
8180
toCreate -> KubernetesDependentResource.super.handleCreate(toCreate, primary, context));
8281
}
8382

@@ -87,7 +86,6 @@ protected R handleUpdate(R actual, R desired, P primary, Context<P> context) {
8786
.orElseThrow()
8887
.updateAndCacheResource(
8988
desired,
90-
context,
9189
toUpdate ->
9290
KubernetesDependentResource.super.handleUpdate(actual, toUpdate, primary, context));
9391
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@
3333
import io.fabric8.kubernetes.client.dsl.base.PatchContext;
3434
import io.fabric8.kubernetes.client.dsl.base.PatchType;
3535
import io.javaoperatorsdk.operator.OperatorException;
36-
import io.javaoperatorsdk.operator.ReconcilerUtils;
36+
import io.javaoperatorsdk.operator.ReconcilerUtilsInternal;
3737
import io.javaoperatorsdk.operator.api.config.Cloner;
3838
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
3939
import io.javaoperatorsdk.operator.api.reconciler.BaseControl;
4040
import io.javaoperatorsdk.operator.api.reconciler.Context;
4141
import io.javaoperatorsdk.operator.api.reconciler.DefaultContext;
4242
import io.javaoperatorsdk.operator.api.reconciler.DeleteControl;
43+
import io.javaoperatorsdk.operator.api.reconciler.ReconcilerUtils;
4344
import io.javaoperatorsdk.operator.api.reconciler.RetryInfo;
4445
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
4546
import io.javaoperatorsdk.operator.processing.Controller;
@@ -203,7 +204,7 @@ private PostExecutionControl<P> reconcileExecution(
203204
}
204205

205206
if (updateControl.isPatchStatus()) {
206-
customResourceFacade.patchStatus(toUpdate, originalResource);
207+
customResourceFacade.patchStatus(context, toUpdate, originalResource);
207208
}
208209
return createPostExecutionControl(updatedCustomResource, updateControl, executionScope);
209210
}
@@ -241,7 +242,7 @@ public boolean isLastAttempt() {
241242
try {
242243
updatedResource =
243244
customResourceFacade.patchStatus(
244-
errorStatusUpdateControl.getResource().orElseThrow(), originalResource);
245+
context, errorStatusUpdateControl.getResource().orElseThrow(), originalResource);
245246
} catch (Exception ex) {
246247
int code = ex instanceof KubernetesClientException kcex ? kcex.getCode() : -1;
247248
Level exceptionLevel = Level.ERROR;
@@ -529,20 +530,14 @@ public R patchResource(R resource, R originalResource) {
529530
}
530531
}
531532

532-
public R patchStatus(R resource, R originalResource) {
533+
public R patchStatus(Context<R> context, R resource, R originalResource) {
533534
log.trace("Patching status for resource: {} with ssa: {}", resource, useSSA);
534535
if (useSSA) {
535536
var managedFields = resource.getMetadata().getManagedFields();
536537
try {
537538
resource.getMetadata().setManagedFields(null);
538539
var res = resource(resource);
539-
return res.subresource("status")
540-
.patch(
541-
new PatchContext.Builder()
542-
.withFieldManager(fieldManager)
543-
.withForce(true)
544-
.withPatchType(PatchType.SERVER_SIDE_APPLY)
545-
.build());
540+
return ReconcilerUtils.ssaStatusPrimary(context, resource);
546541
} finally {
547542
resource.getMetadata().setManagedFields(managedFields);
548543
}
@@ -562,7 +557,7 @@ private R editStatus(R resource, R originalResource) {
562557
var res = resource(clonedOriginal);
563558
return res.editStatus(
564559
r -> {
565-
ReconcilerUtils.setStatus(r, ReconcilerUtils.getStatus(resource));
560+
ReconcilerUtilsInternal.setStatus(r, ReconcilerUtilsInternal.getStatus(resource));
566561
return r;
567562
});
568563
} finally {

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/controller/ControllerEventSource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
import io.javaoperatorsdk.operator.processing.event.source.filter.OnUpdateFilter;
3333
import io.javaoperatorsdk.operator.processing.event.source.informer.ManagedInformerEventSource;
3434

35-
import static io.javaoperatorsdk.operator.ReconcilerUtils.handleKubernetesClientException;
35+
import static io.javaoperatorsdk.operator.ReconcilerUtilsInternal.handleKubernetesClientException;
3636
import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getVersion;
3737
import static io.javaoperatorsdk.operator.processing.event.source.controller.InternalEventFilters.*;
3838

0 commit comments

Comments
 (0)