Skip to content

Commit 879e070

Browse files
committed
feat: handle clustered resource on secondary to primary mapper init (#2321)
Fixes #2311 Overriding getPrimaryResourceType should allow to make things work even in deeper hierarchies. Signed-off-by: Chris Laprun <[email protected]> Signed-off-by: Attila Mészáros <[email protected]>
1 parent 1ea47c5 commit 879e070

File tree

6 files changed

+65
-26
lines changed

6 files changed

+65
-26
lines changed

Diff for: operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Utils.java

+21-16
Original file line numberDiff line numberDiff line change
@@ -103,21 +103,22 @@ static boolean getBooleanFromSystemPropsOrDefault(String propertyName, boolean d
103103
return defaultValue;
104104
} else {
105105
property = property.trim().toLowerCase();
106-
switch (property) {
107-
case "true":
108-
return true;
109-
case "false":
110-
return false;
111-
default:
112-
return defaultValue;
113-
}
106+
return switch (property) {
107+
case "true" -> true;
108+
case "false" -> false;
109+
default -> defaultValue;
110+
};
114111
}
115112
}
116113

117114
public static Class<?> getFirstTypeArgumentFromExtendedClass(Class<?> clazz) {
115+
return getTypeArgumentFromExtendedClassByIndex(clazz, 0);
116+
}
117+
118+
public static Class<?> getTypeArgumentFromExtendedClassByIndex(Class<?> clazz, int index) {
118119
try {
119120
Type type = clazz.getGenericSuperclass();
120-
return (Class<?>) ((ParameterizedType) type).getActualTypeArguments()[0];
121+
return (Class<?>) ((ParameterizedType) type).getActualTypeArguments()[index];
121122
} catch (Exception e) {
122123
throw new RuntimeException(GENERIC_PARAMETER_TYPE_ERROR_PREFIX
123124
+ clazz.getSimpleName()
@@ -186,27 +187,31 @@ private static Optional<? extends Class<?>> extractType(Class<?> clazz,
186187

187188
public static Class<?> getFirstTypeArgumentFromSuperClassOrInterface(Class<?> clazz,
188189
Class<?> expectedImplementedInterface) {
190+
return getTypeArgumentFromSuperClassOrInterfaceByIndex(clazz, expectedImplementedInterface, 0);
191+
}
192+
193+
public static Class<?> getTypeArgumentFromSuperClassOrInterfaceByIndex(Class<?> clazz,
194+
Class<?> expectedImplementedInterface, int index) {
189195
// first check super class if it exists
190196
try {
191197
final Class<?> superclass = clazz.getSuperclass();
192198
if (!superclass.equals(Object.class)) {
193199
try {
194-
return getFirstTypeArgumentFromExtendedClass(clazz);
200+
return getTypeArgumentFromExtendedClassByIndex(clazz, index);
195201
} catch (Exception e) {
196202
// try interfaces
197203
try {
198-
return getFirstTypeArgumentFromInterface(clazz, expectedImplementedInterface);
204+
return getTypeArgumentFromInterfaceByIndex(clazz, expectedImplementedInterface, index);
199205
} catch (Exception ex) {
200206
// try on the parent
201-
return getFirstTypeArgumentFromSuperClassOrInterface(superclass,
202-
expectedImplementedInterface);
207+
return getTypeArgumentFromSuperClassOrInterfaceByIndex(superclass,
208+
expectedImplementedInterface, index);
203209
}
204210
}
205211
}
206-
return getFirstTypeArgumentFromInterface(clazz, expectedImplementedInterface);
212+
return getTypeArgumentFromInterfaceByIndex(clazz, expectedImplementedInterface, index);
207213
} catch (Exception e) {
208-
throw new OperatorException(
209-
GENERIC_PARAMETER_TYPE_ERROR_PREFIX + clazz.getSimpleName(), e);
214+
throw new OperatorException(GENERIC_PARAMETER_TYPE_ERROR_PREFIX + clazz.getSimpleName(), e);
210215
}
211216
}
212217

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

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.fabric8.kubernetes.api.model.GenericKubernetesResource;
44
import io.fabric8.kubernetes.api.model.HasMetadata;
5+
import io.javaoperatorsdk.operator.api.config.Utils;
56
import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration;
67
import io.javaoperatorsdk.operator.processing.GroupVersionKind;
78

@@ -23,8 +24,14 @@ protected InformerConfiguration.InformerConfigurationBuilder<GenericKubernetesRe
2324
return InformerConfiguration.from(groupVersionKind);
2425
}
2526

27+
@SuppressWarnings("unchecked")
28+
@Override
29+
protected Class<P> getPrimaryResourceType() {
30+
return (Class<P>) Utils.getFirstTypeArgumentFromExtendedClass(getClass());
31+
}
32+
2633
@SuppressWarnings("unused")
27-
public GroupVersionKindPlural getGroupVersionKind() {
34+
public GroupVersionKind getGroupVersionKind() {
2835
return groupVersionKind;
2936
}
3037
}

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

+19-6
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
import org.slf4j.LoggerFactory;
1010

1111
import io.fabric8.kubernetes.api.model.HasMetadata;
12+
import io.fabric8.kubernetes.api.model.Namespaced;
1213
import io.fabric8.kubernetes.client.dsl.Resource;
1314
import io.javaoperatorsdk.operator.OperatorException;
1415
import io.javaoperatorsdk.operator.ReconcilerUtils;
16+
import io.javaoperatorsdk.operator.api.config.Utils;
1517
import io.javaoperatorsdk.operator.api.config.dependent.Configured;
1618
import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration;
1719
import io.javaoperatorsdk.operator.api.reconciler.Constants;
@@ -36,8 +38,12 @@ public abstract class KubernetesDependentResource<R extends HasMetadata, P exten
3638
implements DependentResourceConfigurator<KubernetesDependentResourceConfig<R>> {
3739

3840
private static final Logger log = LoggerFactory.getLogger(KubernetesDependentResource.class);
39-
private final ResourceUpdaterMatcher<R> updaterMatcher;
4041
private final boolean garbageCollected = this instanceof GarbageCollected;
42+
@SuppressWarnings("unchecked")
43+
private final ResourceUpdaterMatcher<R> updaterMatcher = this instanceof ResourceUpdaterMatcher
44+
? (ResourceUpdaterMatcher<R>) this
45+
: GenericResourceUpdaterMatcher.updaterMatcherFor(resourceType());
46+
private final boolean clustered;
4147
private KubernetesDependentResourceConfig<R> kubernetesDependentResourceConfig;
4248
private volatile Boolean useSSA;
4349

@@ -46,16 +52,23 @@ public KubernetesDependentResource(Class<R> resourceType) {
4652
this(resourceType, null);
4753
}
4854

49-
@SuppressWarnings("unchecked")
5055
public KubernetesDependentResource(Class<R> resourceType, String name) {
5156
super(resourceType, name);
57+
final var primaryResourceType = getPrimaryResourceType();
58+
clustered = !Namespaced.class.isAssignableFrom(primaryResourceType);
59+
}
5260

53-
updaterMatcher = this instanceof ResourceUpdaterMatcher
54-
? (ResourceUpdaterMatcher<R>) this
55-
: GenericResourceUpdaterMatcher.updaterMatcherFor(resourceType);
61+
protected KubernetesDependentResource(Class<R> resourceType, String name,
62+
boolean primaryIsClustered) {
63+
super(resourceType, name);
64+
clustered = primaryIsClustered;
5665
}
5766

5867
@SuppressWarnings("unchecked")
68+
protected Class<P> getPrimaryResourceType() {
69+
return (Class<P>) Utils.getTypeArgumentFromExtendedClassByIndex(getClass(), 1);
70+
}
71+
5972
@Override
6073
public void configureWith(KubernetesDependentResourceConfig<R> config) {
6174
this.kubernetesDependentResourceConfig = config;
@@ -87,7 +100,7 @@ private SecondaryToPrimaryMapper<R> getSecondaryToPrimaryMapper() {
87100
if (this instanceof SecondaryToPrimaryMapper) {
88101
return (SecondaryToPrimaryMapper<R>) this;
89102
} else if (garbageCollected) {
90-
return Mappers.fromOwnerReferences(false);
103+
return Mappers.fromOwnerReferences(clustered);
91104
} else if (useNonOwnerRefBasedSecondaryToPrimaryMapping()) {
92105
return Mappers.fromDefaultAnnotations();
93106
} else {

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

+5
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ public TestDependent(String name) {
3939
super(ConfigMap.class, name);
4040
}
4141

42+
@Override
43+
protected Class<TestCustomResource> getPrimaryResourceType() {
44+
return TestCustomResource.class;
45+
}
46+
4247
@Override
4348
public ReconcileResult<ConfigMap> reconcile(TestCustomResource primary,
4449
Context<TestCustomResource> context) {

Diff for: operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/bulkdependent/ConfigMapDeleterBulkDependentResource.java

+7-3
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,24 @@ public ConfigMapDeleterBulkDependentResource() {
3434
super(ConfigMap.class);
3535
}
3636

37+
@Override
38+
protected Class<BulkDependentTestCustomResource> getPrimaryResourceType() {
39+
return BulkDependentTestCustomResource.class;
40+
}
41+
3742
@Override
3843
public Map<String, ConfigMap> desiredResources(BulkDependentTestCustomResource primary,
3944
Context<BulkDependentTestCustomResource> context) {
4045
var number = primary.getSpec().getNumberOfResources();
4146
Map<String, ConfigMap> res = new HashMap<>();
4247
for (int i = 0; i < number; i++) {
4348
var key = Integer.toString(i);
44-
res.put(key, desired(primary, key, context));
49+
res.put(key, desired(primary, key));
4550
}
4651
return res;
4752
}
4853

49-
public ConfigMap desired(BulkDependentTestCustomResource primary, String key,
50-
Context<BulkDependentTestCustomResource> context) {
54+
public ConfigMap desired(BulkDependentTestCustomResource primary, String key) {
5155
ConfigMap configMap = new ConfigMap();
5256
configMap.setMetadata(new ObjectMetaBuilder()
5357
.withName(primary.getMetadata().getName() + INDEX_DELIMITER + key)

Diff for: operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/complexdependent/dependent/BaseDependentResource.java

+5
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ public BaseDependentResource(Class<R> resourceType, String component) {
1616
this.component = component;
1717
}
1818

19+
@Override
20+
protected Class<ComplexDependentCustomResource> getPrimaryResourceType() {
21+
return ComplexDependentCustomResource.class;
22+
}
23+
1924
protected String name(ComplexDependentCustomResource primary) {
2025
return String.format("%s-%s", component, primary.getSpec().getProjectId());
2126
}

0 commit comments

Comments
 (0)