Skip to content

Commit 94dabb4

Browse files
csvirimetacosm
authored andcommitted
refactor: updateMatcher removal (#2431)
1 parent 03862cc commit 94dabb4

File tree

5 files changed

+46
-108
lines changed

5 files changed

+46
-108
lines changed

Diff for: operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcher.java

+13-43
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,14 @@
44
import java.util.Collections;
55
import java.util.List;
66

7-
import io.fabric8.kubernetes.api.model.ConfigMap;
87
import io.fabric8.kubernetes.api.model.HasMetadata;
9-
import io.fabric8.kubernetes.api.model.Secret;
108
import io.fabric8.zjsonpatch.JsonDiff;
119
import io.javaoperatorsdk.operator.api.reconciler.Context;
1210
import io.javaoperatorsdk.operator.processing.dependent.Matcher;
1311

1412
import com.fasterxml.jackson.databind.JsonNode;
1513

16-
public class GenericKubernetesResourceMatcher<R extends HasMetadata, P extends HasMetadata>
17-
implements Matcher<R, P> {
14+
public class GenericKubernetesResourceMatcher<R extends HasMetadata, P extends HasMetadata> {
1815

1916
private static final String SPEC = "/spec";
2017
private static final String METADATA = "/metadata";
@@ -26,40 +23,7 @@ public class GenericKubernetesResourceMatcher<R extends HasMetadata, P extends H
2623

2724
private static final String PATH = "path";
2825
private static final String[] EMPTY_ARRAY = {};
29-
private final KubernetesDependentResource<R, P> dependentResource;
3026

31-
private GenericKubernetesResourceMatcher(KubernetesDependentResource<R, P> dependentResource) {
32-
this.dependentResource = dependentResource;
33-
}
34-
35-
@SuppressWarnings({"unchecked", "rawtypes", "unused"})
36-
static <R extends HasMetadata, P extends HasMetadata> Matcher<R, P> matcherFor(
37-
KubernetesDependentResource<R, P> dependentResource) {
38-
return new GenericKubernetesResourceMatcher(dependentResource);
39-
}
40-
41-
/**
42-
* {@inheritDoc}
43-
* <p>
44-
* This implementation attempts to cover most common cases out of the box by considering
45-
* non-additive changes to the resource's spec (if the resource in question has a {@code spec}
46-
* field), making special provisions for {@link ConfigMap} and {@link Secret} resources. Additive
47-
* changes (i.e. a field is added that previously didn't exist) are not considered as triggering a
48-
* mismatch by default to account for validating webhooks that might add default values
49-
* automatically when not present or some other controller adding labels and/or annotations.
50-
* </p>
51-
* <p>
52-
* It should be noted that this implementation is potentially intensive because it generically
53-
* attempts to cover common use cases by performing diffs on the JSON representation of objects.
54-
* If performance is a concern, it might be easier / simpler to provide a {@link Matcher}
55-
* implementation optimized for your use case.
56-
* </p>
57-
*/
58-
@Override
59-
public Result<R> match(R actualResource, P primary, Context<P> context) {
60-
var desired = dependentResource.desired(primary, context);
61-
return match(desired, actualResource, false, false, context);
62-
}
6327

6428
/**
6529
* Determines whether the specified actual resource matches the specified desired resource,
@@ -84,14 +48,20 @@ public Result<R> match(R actualResource, P primary, Context<P> context) {
8448
* @param <R> resource
8549
* @return results of matching
8650
*/
87-
public static <R extends HasMetadata, P extends HasMetadata> Result<R> match(R desired,
51+
public static <R extends HasMetadata, P extends HasMetadata> Matcher.Result<R> match(R desired,
8852
R actualResource,
8953
boolean labelsAndAnnotationsEquality,
9054
boolean valuesEquality, Context<P> context) {
9155
return match(desired, actualResource,
9256
labelsAndAnnotationsEquality, valuesEquality, context, EMPTY_ARRAY);
9357
}
9458

59+
public static <R extends HasMetadata, P extends HasMetadata> Matcher.Result<R> match(R desired,
60+
R actualResource, Context<P> context) {
61+
return match(desired, actualResource,
62+
false, false, context, EMPTY_ARRAY);
63+
}
64+
9565
/**
9666
* Determines whether the specified actual resource matches the specified desired resource,
9767
* possibly considering metadata and deeper equality checks.
@@ -108,7 +78,7 @@ public static <R extends HasMetadata, P extends HasMetadata> Result<R> match(R d
10878
* @param <R> resource
10979
* @return results of matching
11080
*/
111-
public static <R extends HasMetadata, P extends HasMetadata> Result<R> match(R desired,
81+
public static <R extends HasMetadata, P extends HasMetadata> Matcher.Result<R> match(R desired,
11282
R actualResource,
11383
boolean labelsAndAnnotationsEquality,
11484
Context<P> context, String... ignorePaths) {
@@ -139,7 +109,7 @@ public static <R extends HasMetadata, P extends HasMetadata> Result<R> match(R d
139109
* match fails.
140110
* @return a {@link io.javaoperatorsdk.operator.processing.dependent.Matcher.Result} object
141111
*/
142-
public static <R extends HasMetadata, P extends HasMetadata> Result<R> match(
112+
public static <R extends HasMetadata, P extends HasMetadata> Matcher.Result<R> match(
143113
KubernetesDependentResource<R, P> dependentResource, R actualResource, P primary,
144114
Context<P> context,
145115
boolean labelsAndAnnotationsEquality,
@@ -150,7 +120,7 @@ public static <R extends HasMetadata, P extends HasMetadata> Result<R> match(
150120
ignorePaths);
151121
}
152122

153-
public static <R extends HasMetadata, P extends HasMetadata> Result<R> match(
123+
public static <R extends HasMetadata, P extends HasMetadata> Matcher.Result<R> match(
154124
KubernetesDependentResource<R, P> dependentResource, R actualResource, P primary,
155125
Context<P> context,
156126
boolean specEquality,
@@ -161,7 +131,7 @@ public static <R extends HasMetadata, P extends HasMetadata> Result<R> match(
161131
labelsAndAnnotationsEquality, specEquality, context, ignorePaths);
162132
}
163133

164-
public static <R extends HasMetadata, P extends HasMetadata> Result<R> match(R desired,
134+
public static <R extends HasMetadata, P extends HasMetadata> Matcher.Result<R> match(R desired,
165135
R actualResource, boolean labelsAndAnnotationsEquality, boolean valuesEquality,
166136
Context<P> context,
167137
String... ignoredPaths) {
@@ -194,7 +164,7 @@ public static <R extends HasMetadata, P extends HasMetadata> Result<R> match(R d
194164
}
195165
}
196166

197-
return Result.computed(matched, desired);
167+
return Matcher.Result.computed(matched, desired);
198168
}
199169

200170
private static boolean match(boolean equality, JsonNode diff,
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,17 @@
1-
package io.javaoperatorsdk.operator.processing.dependent.kubernetes.updatermatcher;
1+
package io.javaoperatorsdk.operator.processing.dependent.kubernetes;
22

33
import java.util.Map;
44

55
import io.fabric8.kubernetes.api.model.HasMetadata;
66
import io.fabric8.kubernetes.client.utils.KubernetesSerialization;
77
import io.javaoperatorsdk.operator.api.reconciler.Context;
8-
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.GenericKubernetesResourceMatcher;
9-
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.ResourceUpdaterMatcher;
108

11-
public class GenericResourceUpdaterMatcher<R extends HasMetadata> implements
12-
ResourceUpdaterMatcher<R> {
9+
public class GenericResourceUpdater {
1310

1411
private static final String METADATA = "metadata";
15-
private static final ResourceUpdaterMatcher<?> INSTANCE = new GenericResourceUpdaterMatcher<>();
16-
17-
protected GenericResourceUpdaterMatcher() {}
18-
19-
@SuppressWarnings("unchecked")
20-
public static <R extends HasMetadata> ResourceUpdaterMatcher<R> updaterMatcherFor() {
21-
return (ResourceUpdaterMatcher<R>) INSTANCE;
22-
}
2312

2413
@SuppressWarnings("unchecked")
25-
@Override
26-
public R updateResource(R actual, R desired, Context<?> context) {
14+
public static <R extends HasMetadata> R updateResource(R actual, R desired, Context<?> context) {
2715
KubernetesSerialization kubernetesSerialization =
2816
context.getClient().getKubernetesSerialization();
2917
Map<String, Object> actualMap = kubernetesSerialization.convertValue(actual, Map.class);
@@ -40,12 +28,6 @@ public R updateResource(R actual, R desired, Context<?> context) {
4028
return clonedActual;
4129
}
4230

43-
@Override
44-
public boolean matches(R actual, R desired, Context<?> context) {
45-
return GenericKubernetesResourceMatcher.match(desired, actual,
46-
false, false, context).matched();
47-
}
48-
4931
public static <K extends HasMetadata> void updateLabelsAndAnnotation(K actual, K desired) {
5032
actual.getMetadata().getLabels().putAll(desired.getMetadata().getLabels());
5133
actual.getMetadata().getAnnotations().putAll(desired.getMetadata().getAnnotations());

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

+6-17
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ConfiguredDependentResource;
2222
import io.javaoperatorsdk.operator.processing.dependent.AbstractEventSourceHolderDependentResource;
2323
import io.javaoperatorsdk.operator.processing.dependent.Matcher.Result;
24-
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.updatermatcher.GenericResourceUpdaterMatcher;
2524
import io.javaoperatorsdk.operator.processing.event.ResourceID;
2625
import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper;
2726
import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
@@ -38,10 +37,7 @@ public abstract class KubernetesDependentResource<R extends HasMetadata, P exten
3837
private static final Logger log = LoggerFactory.getLogger(KubernetesDependentResource.class);
3938
private final boolean garbageCollected = this instanceof GarbageCollected;
4039
private final boolean usingCustomResourceUpdateMatcher = this instanceof ResourceUpdaterMatcher;
41-
@SuppressWarnings("unchecked")
42-
private final ResourceUpdaterMatcher<R> updaterMatcher = usingCustomResourceUpdateMatcher
43-
? (ResourceUpdaterMatcher<R>) this
44-
: GenericResourceUpdaterMatcher.updaterMatcherFor();
40+
4541
private KubernetesDependentResourceConfig<R> kubernetesDependentResourceConfig;
4642

4743
public KubernetesDependentResource(Class<R> resourceType) {
@@ -57,7 +53,6 @@ public void configureWith(KubernetesDependentResourceConfig<R> config) {
5753
this.kubernetesDependentResourceConfig = config;
5854
}
5955

60-
6156
@SuppressWarnings("unused")
6257
public R create(R desired, P primary, Context<P> context) {
6358
if (useSSA(context)) {
@@ -91,7 +86,7 @@ public R update(R actual, R desired, P primary, Context<P> context) {
9186
.fieldManager(context.getControllerConfiguration().fieldManager())
9287
.forceConflicts().serverSideApply();
9388
} else {
94-
var updatedActual = updaterMatcher.updateResource(actual, desired, context);
89+
var updatedActual = GenericResourceUpdater.updateResource(actual, desired, context);
9590
updatedResource = prepare(context, updatedActual, primary, "Updating").update();
9691
}
9792
log.debug("Resource version after update: {}",
@@ -102,25 +97,19 @@ public R update(R actual, R desired, P primary, Context<P> context) {
10297
@Override
10398
public Result<R> match(R actualResource, P primary, Context<P> context) {
10499
final var desired = desired(primary, context);
105-
return match(actualResource, desired, primary, updaterMatcher, context);
106-
}
107-
108-
@SuppressWarnings({"unused"})
109-
public Result<R> match(R actualResource, R desired, P primary, Context<P> context) {
110-
return match(actualResource, desired, primary,
111-
GenericResourceUpdaterMatcher.updaterMatcherFor(),
112-
context);
100+
return match(actualResource, desired, primary, context);
113101
}
114102

115-
public Result<R> match(R actualResource, R desired, P primary, ResourceUpdaterMatcher<R> matcher,
103+
public Result<R> match(R actualResource, R desired, P primary,
116104
Context<P> context) {
117105
final boolean matches;
118106
addMetadata(true, actualResource, desired, primary, context);
119107
if (useSSA(context)) {
120108
matches = SSABasedGenericKubernetesResourceMatcher.getInstance()
121109
.matches(actualResource, desired, context);
122110
} else {
123-
matches = matcher.matches(actualResource, desired, context);
111+
matches = GenericKubernetesResourceMatcher.match(desired, actualResource,
112+
false, false, context).matched();
124113
}
125114
return Result.computed(matches, desired);
126115
}

Diff for: operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcherTest.java

+15-13
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,21 @@
1313
import io.javaoperatorsdk.operator.MockKubernetesClient;
1414
import io.javaoperatorsdk.operator.ReconcilerUtils;
1515
import io.javaoperatorsdk.operator.api.reconciler.Context;
16-
import io.javaoperatorsdk.operator.processing.dependent.Matcher;
17-
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.updatermatcher.GenericResourceUpdaterMatcher;
1816

1917
import static io.javaoperatorsdk.operator.processing.dependent.kubernetes.GenericKubernetesResourceMatcher.match;
2018
import static org.assertj.core.api.Assertions.assertThat;
2119
import static org.mockito.Mockito.mock;
2220
import static org.mockito.Mockito.when;
2321

24-
@SuppressWarnings({"unchecked", "rawtypes"})
22+
@SuppressWarnings({"unchecked"})
2523
class GenericKubernetesResourceMatcherTest {
2624

2725
private static final Context context = mock(Context.class);
2826

2927
Deployment actual = createDeployment();
3028
Deployment desired = createDeployment();
3129
TestDependentResource dependentResource = new TestDependentResource(desired);
32-
Matcher matcher = GenericKubernetesResourceMatcher.matcherFor(dependentResource);
30+
3331

3432
@BeforeAll
3533
static void setUp() {
@@ -39,15 +37,17 @@ static void setUp() {
3937

4038
@Test
4139
void matchesTrivialCases() {
42-
assertThat(matcher.match(actual, null, context).matched()).isTrue();
43-
assertThat(matcher.match(actual, null, context).computedDesired()).isPresent();
44-
assertThat(matcher.match(actual, null, context).computedDesired()).contains(desired);
40+
assertThat(GenericKubernetesResourceMatcher.match(desired, actual, context).matched()).isTrue();
41+
assertThat(GenericKubernetesResourceMatcher.match(desired, actual, context).computedDesired())
42+
.isPresent();
43+
assertThat(GenericKubernetesResourceMatcher.match(desired, actual, context).computedDesired())
44+
.contains(desired);
4545
}
4646

4747
@Test
4848
void matchesAdditiveOnlyChanges() {
4949
actual.getSpec().getTemplate().getMetadata().getLabels().put("new-key", "val");
50-
assertThat(matcher.match(actual, null, context).matched())
50+
assertThat(GenericKubernetesResourceMatcher.match(desired, actual, context).matched())
5151
.withFailMessage("Additive changes should not cause a mismatch by default")
5252
.isTrue();
5353
}
@@ -64,7 +64,9 @@ void matchesWithStrongSpecEquality() {
6464
@Test
6565
void doesNotMatchRemovedValues() {
6666
actual = createDeployment();
67-
assertThat(matcher.match(actual, createPrimary("removed"), context).matched())
67+
assertThat(GenericKubernetesResourceMatcher
68+
.match(dependentResource.desired(createPrimary("removed"), null), actual, context)
69+
.matched())
6870
.withFailMessage("Removing values in metadata should lead to a mismatch")
6971
.isFalse();
7072
}
@@ -73,7 +75,7 @@ void doesNotMatchRemovedValues() {
7375
void doesNotMatchChangedValues() {
7476
actual = createDeployment();
7577
actual.getSpec().setReplicas(2);
76-
assertThat(matcher.match(actual, null, context).matched())
78+
assertThat(GenericKubernetesResourceMatcher.match(desired, actual, context).matched())
7779
.withFailMessage("Should not have matched because values have changed")
7880
.isFalse();
7981
}
@@ -82,7 +84,7 @@ void doesNotMatchChangedValues() {
8284
void ignoreStatus() {
8385
actual = createDeployment();
8486
actual.setStatus(new DeploymentStatusBuilder().withReadyReplicas(1).build());
85-
assertThat(matcher.match(actual, null, context).matched())
87+
assertThat(GenericKubernetesResourceMatcher.match(desired, actual, context).matched())
8688
.withFailMessage("Should ignore status in actual")
8789
.isTrue();
8890
}
@@ -146,8 +148,8 @@ void checkServiceAccount() {
146148
.addNewImagePullSecret("imagePullSecret3")
147149
.build();
148150

149-
final var matcher = GenericResourceUpdaterMatcher.<ServiceAccount>updaterMatcherFor();
150-
assertThat(matcher.matches(actual, desired, context)).isTrue();
151+
assertThat(GenericKubernetesResourceMatcher.match(desired, actual, false, false, context)
152+
.matched()).isTrue();
151153
}
152154

153155
@Test

0 commit comments

Comments
 (0)