Skip to content

Commit d51f0e3

Browse files
committed
Revert "remove with lock versions"
This reverts commit 68ca625.
1 parent 42b9ead commit d51f0e3

File tree

11 files changed

+266
-5
lines changed

11 files changed

+266
-5
lines changed

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

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,112 @@
1111
import io.fabric8.kubernetes.client.dsl.base.PatchContext;
1212
import io.fabric8.kubernetes.client.dsl.base.PatchType;
1313
import io.javaoperatorsdk.operator.api.reconciler.support.PrimaryResourceCache;
14+
import io.javaoperatorsdk.operator.processing.event.ResourceID;
1415

1516
public class PrimaryUpdateAndCacheUtils {
1617

1718
private PrimaryUpdateAndCacheUtils() {}
1819

1920
private static final Logger log = LoggerFactory.getLogger(PrimaryUpdateAndCacheUtils.class);
2021

22+
/**
23+
* Makes sure that the up-to-date primary resource will be present during the next reconciliation.
24+
* Using update (PUT) method.
25+
*
26+
* @param primary resource
27+
* @param context of reconciliation
28+
* @return updated resource
29+
* @param <P> primary resource type
30+
*/
31+
public static <P extends HasMetadata> P updateAndCacheStatusWithLock(
32+
P primary, Context<P> context) {
33+
return patchAndCacheStatusWithLock(
34+
primary, context, (p, c) -> c.resource(primary).updateStatus());
35+
}
36+
37+
/**
38+
* Makes sure that the up-to-date primary resource will be present during the next reconciliation.
39+
* Using JSON Merge patch.
40+
*
41+
* @param primary resource
42+
* @param context of reconciliation
43+
* @return updated resource
44+
* @param <P> primary resource type
45+
*/
46+
public static <P extends HasMetadata> P patchAndCacheStatusWithLock(
47+
P primary, Context<P> context) {
48+
return patchAndCacheStatusWithLock(
49+
primary, context, (p, c) -> c.resource(primary).patchStatus());
50+
}
51+
52+
/**
53+
* Makes sure that the up-to-date primary resource will be present during the next reconciliation.
54+
* Using JSON Patch.
55+
*
56+
* @param primary resource
57+
* @param context of reconciliation
58+
* @return updated resource
59+
* @param <P> primary resource type
60+
*/
61+
public static <P extends HasMetadata> P editAndCacheStatusWithLock(
62+
P primary, Context<P> context, UnaryOperator<P> operation) {
63+
return patchAndCacheStatusWithLock(
64+
primary, context, (p, c) -> c.resource(primary).editStatus(operation));
65+
}
66+
67+
/**
68+
* Makes sure that the up-to-date primary resource will be present during the next reconciliation.
69+
*
70+
* @param primary resource
71+
* @param context of reconciliation
72+
* @param patch free implementation of cache - make sure you use optimistic locking during the
73+
* update
74+
* @return the updated resource.
75+
* @param <P> primary resource type
76+
*/
77+
public static <P extends HasMetadata> P patchAndCacheStatusWithLock(
78+
P primary, Context<P> context, BiFunction<P, KubernetesClient, P> patch) {
79+
checkResourceVersionPresent(primary);
80+
var updatedResource = patch.apply(primary, context.getClient());
81+
context
82+
.eventSourceRetriever()
83+
.getControllerEventSource()
84+
.handleRecentResourceUpdate(ResourceID.fromResource(primary), updatedResource, primary);
85+
return updatedResource;
86+
}
87+
88+
/**
89+
* Makes sure that the up-to-date primary resource will be present during the next reconciliation.
90+
* Using Server Side Apply.
91+
*
92+
* @param primary resource
93+
* @param freshResourceWithStatus - fresh resource with target state
94+
* @param context of reconciliation
95+
* @return the updated resource.
96+
* @param <P> primary resource type
97+
*/
98+
public static <P extends HasMetadata> P ssaPatchAndCacheStatusWithLock(
99+
P primary, P freshResourceWithStatus, Context<P> context) {
100+
checkResourceVersionPresent(freshResourceWithStatus);
101+
var res =
102+
context
103+
.getClient()
104+
.resource(freshResourceWithStatus)
105+
.subresource("status")
106+
.patch(
107+
new PatchContext.Builder()
108+
.withForce(true)
109+
.withFieldManager(context.getControllerConfiguration().fieldManager())
110+
.withPatchType(PatchType.SERVER_SIDE_APPLY)
111+
.build());
112+
113+
context
114+
.eventSourceRetriever()
115+
.getControllerEventSource()
116+
.handleRecentResourceUpdate(ResourceID.fromResource(primary), res, primary);
117+
return res;
118+
}
119+
21120
/**
22121
* Patches the resource and adds it to the {@link PrimaryResourceCache} provided. Optimistic
23122
* locking is not required.

operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchPrimaryCacheCustomResource.java renamed to operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/primarycache/StatusPatchPrimaryCacheCustomResource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.javaoperatorsdk.operator.baseapi.statuscache;
1+
package io.javaoperatorsdk.operator.baseapi.statuscache.primarycache;
22

33
import io.fabric8.kubernetes.api.model.Namespaced;
44
import io.fabric8.kubernetes.client.CustomResource;

operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchPrimaryCacheIT.java renamed to operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/primarycache/StatusPatchPrimaryCacheIT.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.javaoperatorsdk.operator.baseapi.statuscache;
1+
package io.javaoperatorsdk.operator.baseapi.statuscache.primarycache;
22

33
import java.time.Duration;
44

operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchPrimaryCacheReconciler.java renamed to operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/primarycache/StatusPatchPrimaryCacheReconciler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.javaoperatorsdk.operator.baseapi.statuscache;
1+
package io.javaoperatorsdk.operator.baseapi.statuscache.primarycache;
22

33
import java.util.List;
44

@@ -12,6 +12,7 @@
1212
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
1313
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
1414
import io.javaoperatorsdk.operator.api.reconciler.support.PrimaryResourceCache;
15+
import io.javaoperatorsdk.operator.baseapi.statuscache.PeriodicTriggerEventSource;
1516
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
1617

1718
@ControllerConfiguration

operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchPrimaryCacheSpec.java renamed to operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/primarycache/StatusPatchPrimaryCacheSpec.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.javaoperatorsdk.operator.baseapi.statuscache;
1+
package io.javaoperatorsdk.operator.baseapi.statuscache.primarycache;
22

33
public class StatusPatchPrimaryCacheSpec {
44

operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/StatusPatchPrimaryCacheStatus.java renamed to operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/statuscache/primarycache/StatusPatchPrimaryCacheStatus.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.javaoperatorsdk.operator.baseapi.statuscache;
1+
package io.javaoperatorsdk.operator.baseapi.statuscache.primarycache;
22

33
public class StatusPatchPrimaryCacheStatus {
44

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.javaoperatorsdk.operator.baseapi.statuscache.withlock;
2+
3+
import io.fabric8.kubernetes.api.model.Namespaced;
4+
import io.fabric8.kubernetes.client.CustomResource;
5+
import io.fabric8.kubernetes.model.annotation.Group;
6+
import io.fabric8.kubernetes.model.annotation.ShortNames;
7+
import io.fabric8.kubernetes.model.annotation.Version;
8+
9+
@Group("sample.javaoperatorsdk")
10+
@Version("v1")
11+
@ShortNames("spcl")
12+
public class StatusPatchCacheWithLockCustomResource
13+
extends CustomResource<StatusPatchCacheWithLockSpec, StatusPatchCacheWithLockStatus>
14+
implements Namespaced {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package io.javaoperatorsdk.operator.baseapi.statuscache.withlock;
2+
3+
import java.time.Duration;
4+
5+
import org.junit.jupiter.api.Test;
6+
import org.junit.jupiter.api.extension.RegisterExtension;
7+
8+
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
9+
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
10+
11+
import static org.assertj.core.api.Assertions.assertThat;
12+
import static org.awaitility.Awaitility.await;
13+
14+
public class StatusPatchCacheWithLockIT {
15+
16+
public static final String TEST_1 = "test1";
17+
18+
@RegisterExtension
19+
LocallyRunOperatorExtension extension =
20+
LocallyRunOperatorExtension.builder()
21+
.withReconciler(StatusPatchCacheWithLockReconciler.class)
22+
.build();
23+
24+
@Test
25+
void testStatusAlwaysUpToDate() {
26+
var reconciler = extension.getReconcilerOfType(StatusPatchCacheWithLockReconciler.class);
27+
28+
extension.create(testResource());
29+
30+
// the reconciliation id periodically triggered, the status values should be increasing
31+
// monotonically
32+
await()
33+
.pollDelay(Duration.ofSeconds(1))
34+
.pollInterval(Duration.ofMillis(30))
35+
.untilAsserted(
36+
() -> {
37+
assertThat(reconciler.errorPresent).isFalse();
38+
assertThat(reconciler.latestValue).isGreaterThan(10);
39+
});
40+
}
41+
42+
StatusPatchCacheWithLockCustomResource testResource() {
43+
var res = new StatusPatchCacheWithLockCustomResource();
44+
res.setMetadata(new ObjectMetaBuilder().withName(TEST_1).build());
45+
res.setSpec(new StatusPatchCacheWithLockSpec());
46+
return res;
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package io.javaoperatorsdk.operator.baseapi.statuscache.withlock;
2+
3+
import java.util.List;
4+
5+
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
6+
import io.javaoperatorsdk.operator.api.reconciler.Context;
7+
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
8+
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
9+
import io.javaoperatorsdk.operator.api.reconciler.PrimaryUpdateAndCacheUtils;
10+
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
11+
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
12+
import io.javaoperatorsdk.operator.baseapi.statuscache.PeriodicTriggerEventSource;
13+
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
14+
15+
@ControllerConfiguration
16+
public class StatusPatchCacheWithLockReconciler
17+
implements Reconciler<StatusPatchCacheWithLockCustomResource> {
18+
19+
public volatile int latestValue = 0;
20+
public volatile boolean errorPresent = false;
21+
22+
@Override
23+
public UpdateControl<StatusPatchCacheWithLockCustomResource> reconcile(
24+
StatusPatchCacheWithLockCustomResource resource,
25+
Context<StatusPatchCacheWithLockCustomResource> context)
26+
throws InterruptedException {
27+
28+
if (resource.getStatus() != null && resource.getStatus().getValue() != latestValue) {
29+
errorPresent = true;
30+
throw new IllegalStateException(
31+
"status is not up to date. Latest value: "
32+
+ latestValue
33+
+ " status values: "
34+
+ resource.getStatus().getValue());
35+
}
36+
37+
var freshCopy = createFreshCopy(resource);
38+
// setting the resource version
39+
freshCopy.getMetadata().setResourceVersion(resource.getMetadata().getResourceVersion());
40+
freshCopy
41+
.getStatus()
42+
.setValue(resource.getStatus() == null ? 1 : resource.getStatus().getValue() + 1);
43+
44+
var updated =
45+
PrimaryUpdateAndCacheUtils.ssaPatchAndCacheStatusWithLock(resource, freshCopy, context);
46+
latestValue = updated.getStatus().getValue();
47+
48+
return UpdateControl.noUpdate();
49+
}
50+
51+
@Override
52+
public List<EventSource<?, StatusPatchCacheWithLockCustomResource>> prepareEventSources(
53+
EventSourceContext<StatusPatchCacheWithLockCustomResource> context) {
54+
// periodic event triggering for testing purposes
55+
return List.of(new PeriodicTriggerEventSource<>(context.getPrimaryCache()));
56+
}
57+
58+
private StatusPatchCacheWithLockCustomResource createFreshCopy(
59+
StatusPatchCacheWithLockCustomResource resource) {
60+
var res = new StatusPatchCacheWithLockCustomResource();
61+
res.setMetadata(
62+
new ObjectMetaBuilder()
63+
.withName(resource.getMetadata().getName())
64+
.withNamespace(resource.getMetadata().getNamespace())
65+
.build());
66+
res.setStatus(new StatusPatchCacheWithLockStatus());
67+
68+
return res;
69+
}
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.javaoperatorsdk.operator.baseapi.statuscache.withlock;
2+
3+
public class StatusPatchCacheWithLockSpec {
4+
5+
private int counter = 0;
6+
7+
public int getCounter() {
8+
return counter;
9+
}
10+
11+
public void setCounter(int counter) {
12+
this.counter = counter;
13+
}
14+
}

0 commit comments

Comments
 (0)