Skip to content

Commit 321ccb7

Browse files
authored
fix: secondary to primary mapper supporting cluster scoped resource (operator-framework#1770)
1 parent 6f6496a commit 321ccb7

File tree

3 files changed

+44
-10
lines changed

3 files changed

+44
-10
lines changed

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

+6-1
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,15 @@ public static ResourceID fromResource(HasMetadata resource) {
1414
}
1515

1616
public static Optional<ResourceID> fromFirstOwnerReference(HasMetadata resource) {
17+
return fromFirstOwnerReference(resource, false);
18+
}
19+
20+
public static Optional<ResourceID> fromFirstOwnerReference(HasMetadata resource,
21+
boolean clusterScoped) {
1722
var ownerReferences = resource.getMetadata().getOwnerReferences();
1823
if (!ownerReferences.isEmpty()) {
1924
return Optional.of(new ResourceID(ownerReferences.get(0).getName(),
20-
resource.getMetadata().getNamespace()));
25+
clusterScoped ? null : resource.getMetadata().getNamespace()));
2126
} else {
2227
return Optional.empty();
2328
}

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/Mappers.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,17 @@ public static <T extends HasMetadata> SecondaryToPrimaryMapper<T> fromLabel(
4242
}
4343

4444
public static <T extends HasMetadata> SecondaryToPrimaryMapper<T> fromOwnerReference() {
45-
return resource -> ResourceID.fromFirstOwnerReference(resource).map(Set::of)
45+
return fromOwnerReference(false);
46+
}
47+
48+
/**
49+
* @param clusterScope if the owner is a cluster scoped resource
50+
* @return mapper
51+
* @param <T> type of the secondary resource, where the owner reference is
52+
*/
53+
public static <T extends HasMetadata> SecondaryToPrimaryMapper<T> fromOwnerReference(
54+
boolean clusterScope) {
55+
return resource -> ResourceID.fromFirstOwnerReference(resource, clusterScope).map(Set::of)
4656
.orElseGet(Collections::emptySet);
4757
}
4858

operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/clusterscopedresource/ClusterScopedCustomResourceReconciler.java

+27-8
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,53 @@
66
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
77
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
88
import io.fabric8.kubernetes.client.KubernetesClient;
9+
import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration;
910
import io.javaoperatorsdk.operator.api.reconciler.*;
1011
import io.javaoperatorsdk.operator.junit.KubernetesClientAware;
12+
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
13+
import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;
14+
import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers;
1115

1216
@ControllerConfiguration
1317
public class ClusterScopedCustomResourceReconciler
14-
implements Reconciler<ClusterScopedCustomResource>, Cleaner<ClusterScopedCustomResource>,
15-
KubernetesClientAware {
18+
implements Reconciler<ClusterScopedCustomResource>,
19+
KubernetesClientAware, EventSourceInitializer<ClusterScopedCustomResource> {
1620

1721
public static final String DATA_KEY = "data-key";
1822

23+
public static final String TEST_LABEL_VALUE = "clusterscopecrtest";
24+
public static final String TEST_LABEL_KEY = "test";
25+
1926
private KubernetesClient client;
2027

2128
@Override
2229
public UpdateControl<ClusterScopedCustomResource> reconcile(
2330
ClusterScopedCustomResource resource, Context<ClusterScopedCustomResource> context) {
2431

25-
client.configMaps().resource(desired(resource)).createOrReplace();
32+
var optionalConfigMap = context.getSecondaryResource(ConfigMap.class);
33+
34+
optionalConfigMap.ifPresentOrElse(cm -> {
35+
if (!resource.getSpec().getData().equals(cm.getData().get(DATA_KEY))) {
36+
client.configMaps().resource(desired(resource)).replace();
37+
}
38+
}, () -> client.configMaps().resource(desired(resource)).create());
2639

2740
resource.setStatus(new ClusterScopedCustomResourceStatus());
2841
resource.getStatus().setCreated(true);
2942
return UpdateControl.patchStatus(resource);
3043
}
3144

3245
private ConfigMap desired(ClusterScopedCustomResource resource) {
33-
return new ConfigMapBuilder()
46+
var cm = new ConfigMapBuilder()
3447
.withMetadata(new ObjectMetaBuilder()
3548
.withName(resource.getMetadata().getName())
3649
.withNamespace(resource.getSpec().getTargetNamespace())
50+
.withLabels(Map.of(TEST_LABEL_KEY, TEST_LABEL_VALUE))
3751
.build())
3852
.withData(Map.of(DATA_KEY, resource.getSpec().getData()))
3953
.build();
54+
cm.addOwnerReference(resource);
55+
return cm;
4056
}
4157

4258
@Override
@@ -50,9 +66,12 @@ public void setKubernetesClient(KubernetesClient kubernetesClient) {
5066
}
5167

5268
@Override
53-
public DeleteControl cleanup(ClusterScopedCustomResource resource,
54-
Context<ClusterScopedCustomResource> context) {
55-
client.configMaps().resource(desired(resource)).delete();
56-
return DeleteControl.defaultDelete();
69+
public Map<String, EventSource> prepareEventSources(
70+
EventSourceContext<ClusterScopedCustomResource> context) {
71+
var ies = new InformerEventSource<>(InformerConfiguration.from(ConfigMap.class, context)
72+
.withSecondaryToPrimaryMapper(Mappers.fromOwnerReference(true))
73+
.withLabelSelector(TEST_LABEL_KEY + "=" + TEST_LABEL_VALUE)
74+
.build(), context);
75+
return EventSourceInitializer.nameEventSources(ies);
5776
}
5877
}

0 commit comments

Comments
 (0)