Skip to content

Commit 16d9d83

Browse files
committed
improve: KubernetesDependentResource uses resource operations directly (#3146)
Signed-off-by: Attila Mészáros <a_meszaros@apple.com>
1 parent a828ec7 commit 16d9d83

File tree

2 files changed

+120
-47
lines changed

2 files changed

+120
-47
lines changed

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceOperations.java

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import io.fabric8.kubernetes.client.dsl.base.PatchType;
2929
import io.javaoperatorsdk.operator.OperatorException;
3030
import io.javaoperatorsdk.operator.processing.event.ResourceID;
31+
import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
3132
import io.javaoperatorsdk.operator.processing.event.source.informer.ManagedInformerEventSource;
3233

3334
import static io.javaoperatorsdk.operator.processing.KubernetesResourceUtils.getUID;
@@ -80,6 +81,40 @@ public <R extends HasMetadata> R serverSideApply(R resource) {
8081
.build()));
8182
}
8283

84+
/**
85+
* Updates the resource and caches the response if needed, thus making sure that next
86+
* reconciliation will see to updated resource - or more recent one if additional update happened
87+
* after this update; In addition to that it filters out the event from the update, so
88+
* reconciliation is not triggered by own update.
89+
*
90+
* <p>You are free to control the optimistic locking by setting the resource version in resource
91+
* metadata. In case of SSA we advise not to do updates with optimistic locking.
92+
*
93+
* @param resource fresh resource for server side apply
94+
* @return updated resource
95+
* @param informerEventSource InformerEventSource to use for resource caching and filtering
96+
* @param <R> resource type
97+
*/
98+
public <R extends HasMetadata> R serverSideApply(
99+
R resource, InformerEventSource<R, P> informerEventSource) {
100+
if (informerEventSource == null) {
101+
return serverSideApply(resource);
102+
}
103+
return resourcePatch(
104+
resource,
105+
r ->
106+
context
107+
.getClient()
108+
.resource(r)
109+
.patch(
110+
new PatchContext.Builder()
111+
.withForce(true)
112+
.withFieldManager(context.getControllerConfiguration().fieldManager())
113+
.withPatchType(PatchType.SERVER_SIDE_APPLY)
114+
.build()),
115+
informerEventSource);
116+
}
117+
83118
/**
84119
* Server-Side Apply the resource status subresource.
85120
*
@@ -189,6 +224,69 @@ public <R extends HasMetadata> R update(R resource) {
189224
return resourcePatch(resource, r -> context.getClient().resource(r).update());
190225
}
191226

227+
/**
228+
* Updates the resource and caches the response if needed, thus making sure that next
229+
* reconciliation will see to updated resource - or more recent one if additional update happened
230+
* after this update; In addition to that it filters out the event from this update, so
231+
* reconciliation is not triggered by own update.
232+
*
233+
* <p>You are free to control the optimistic locking by setting the resource version in resource
234+
* metadata.
235+
*
236+
* @param resource resource to update
237+
* @return updated resource
238+
* @param informerEventSource InformerEventSource to use for resource caching and filtering
239+
* @param <R> resource type
240+
*/
241+
public <R extends HasMetadata> R update(
242+
R resource, InformerEventSource<R, P> informerEventSource) {
243+
if (informerEventSource == null) {
244+
return update(resource);
245+
}
246+
return resourcePatch(
247+
resource, r -> context.getClient().resource(r).update(), informerEventSource);
248+
}
249+
250+
/**
251+
* Creates the resource and caches the response if needed, thus making sure that next
252+
* reconciliation will see to updated resource - or more recent one if additional update happened
253+
* after this update; In addition to that it filters out the event from this update, so
254+
* reconciliation is not triggered by own update.
255+
*
256+
* <p>You are free to control the optimistic locking by setting the resource version in resource
257+
* metadata.
258+
*
259+
* @param resource resource to update
260+
* @return updated resource
261+
* @param <R> resource type
262+
*/
263+
public <R extends HasMetadata> R create(R resource) {
264+
return resourcePatch(resource, r -> context.getClient().resource(r).create());
265+
}
266+
267+
/**
268+
* Creates the resource and caches the response if needed, thus making sure that next
269+
* reconciliation will see to updated resource - or more recent one if additional update happened
270+
* after this update; In addition to that it filters out the event from this update, so
271+
* reconciliation is not triggered by own update.
272+
*
273+
* <p>You are free to control the optimistic locking by setting the resource version in resource
274+
* metadata.
275+
*
276+
* @param resource resource to update
277+
* @return updated resource
278+
* @param informerEventSource InformerEventSource to use for resource caching and filtering
279+
* @param <R> resource type
280+
*/
281+
public <R extends HasMetadata> R create(
282+
R resource, InformerEventSource<R, P> informerEventSource) {
283+
if (informerEventSource == null) {
284+
return create(resource);
285+
}
286+
return resourcePatch(
287+
resource, r -> context.getClient().resource(r).create(), informerEventSource);
288+
}
289+
192290
/**
193291
* Updates the resource status subresource.
194292
*

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

Lines changed: 22 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525

2626
import io.fabric8.kubernetes.api.model.HasMetadata;
2727
import io.fabric8.kubernetes.api.model.Namespaced;
28-
import io.fabric8.kubernetes.client.dsl.Resource;
2928
import io.javaoperatorsdk.operator.api.config.dependent.Configured;
3029
import io.javaoperatorsdk.operator.api.config.informer.InformerEventSourceConfiguration;
3130
import io.javaoperatorsdk.operator.api.reconciler.Context;
@@ -71,28 +70,10 @@ public void configureWith(KubernetesDependentResourceConfig<R> config) {
7170
this.kubernetesDependentResourceConfig = config;
7271
}
7372

74-
@Override
75-
protected R handleCreate(R desired, P primary, Context<P> context) {
76-
return eventSource()
77-
.orElseThrow()
78-
.eventFilteringUpdateAndCacheResource(
79-
desired,
80-
toCreate -> KubernetesDependentResource.super.handleCreate(toCreate, primary, context));
81-
}
82-
83-
@Override
84-
protected R handleUpdate(R actual, R desired, P primary, Context<P> context) {
85-
return eventSource()
86-
.orElseThrow()
87-
.eventFilteringUpdateAndCacheResource(
88-
desired,
89-
toUpdate ->
90-
KubernetesDependentResource.super.handleUpdate(actual, toUpdate, primary, context));
91-
}
92-
9373
@SuppressWarnings("unused")
9474
public R create(R desired, P primary, Context<P> context) {
95-
if (useSSA(context)) {
75+
var ssa = useSSA(context);
76+
if (ssa) {
9677
// setting resource version for SSA so only created if it doesn't exist already
9778
var createIfNotExisting =
9879
kubernetesDependentResourceConfig == null
@@ -104,35 +85,40 @@ public R create(R desired, P primary, Context<P> context) {
10485
}
10586
}
10687
addMetadata(false, null, desired, primary, context);
107-
final var resource = prepare(context, desired, primary, "Creating");
108-
return useSSA(context)
109-
? resource
110-
.fieldManager(context.getControllerConfiguration().fieldManager())
111-
.forceConflicts()
112-
.serverSideApply()
113-
: resource.create();
88+
log.debug(
89+
"Creating target resource with type: {}, with id: {} use ssa: {}",
90+
desired.getClass(),
91+
ResourceID.fromResource(desired),
92+
ssa);
93+
94+
return ssa
95+
? context.resourceOperations().serverSideApply(desired, eventSource().orElse(null))
96+
: context.resourceOperations().create(desired, eventSource().orElse(null));
11497
}
11598

11699
public R update(R actual, R desired, P primary, Context<P> context) {
117-
boolean useSSA = useSSA(context);
100+
boolean ssa = useSSA(context);
118101
if (log.isDebugEnabled()) {
119102
log.debug(
120103
"Updating actual resource: {} version: {}; SSA: {}",
121104
ResourceID.fromResource(actual),
122105
actual.getMetadata().getResourceVersion(),
123-
useSSA);
106+
ssa);
124107
}
125108
R updatedResource;
126109
addMetadata(false, actual, desired, primary, context);
127-
if (useSSA) {
110+
log.debug(
111+
"Updating target resource with type: {}, with id: {} use ssa: {}",
112+
desired.getClass(),
113+
ResourceID.fromResource(desired),
114+
ssa);
115+
if (ssa) {
128116
updatedResource =
129-
prepare(context, desired, primary, "Updating")
130-
.fieldManager(context.getControllerConfiguration().fieldManager())
131-
.forceConflicts()
132-
.serverSideApply();
117+
context.resourceOperations().serverSideApply(desired, eventSource().orElse(null));
133118
} else {
134119
var updatedActual = GenericResourceUpdater.updateResource(actual, desired, context);
135-
updatedResource = prepare(context, updatedActual, primary, "Updating").update();
120+
updatedResource =
121+
context.resourceOperations().update(updatedActual, eventSource().orElse(null));
136122
}
137123
log.debug(
138124
"Resource version after update: {}", updatedResource.getMetadata().getResourceVersion());
@@ -203,17 +189,6 @@ public void deleteTargetResource(P primary, R resource, ResourceID key, Context<
203189
context.getClient().resource(resource).delete();
204190
}
205191

206-
@SuppressWarnings("unused")
207-
protected Resource<R> prepare(Context<P> context, R desired, P primary, String actionName) {
208-
log.debug(
209-
"{} target resource with type: {}, with id: {}",
210-
actionName,
211-
desired.getClass(),
212-
ResourceID.fromResource(desired));
213-
214-
return context.getClient().resource(desired);
215-
}
216-
217192
protected void addReferenceHandlingMetadata(R desired, P primary) {
218193
if (addOwnerReference()) {
219194
desired.addOwnerReference(primary);

0 commit comments

Comments
 (0)