Skip to content

Commit 9184633

Browse files
authored
fix: potential bug in informers (#833)
1 parent a22596e commit 9184633

File tree

4 files changed

+50
-9
lines changed

4 files changed

+50
-9
lines changed

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

+7
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@ public void onAdd(T t) {
8383

8484
@Override
8585
public void onUpdate(T oldObject, T newObject) {
86+
if (newObject == null) {
87+
// this is a fix for this potential issue with informer:
88+
// https://github.com/java-operator-sdk/java-operator-sdk/issues/830
89+
propagateEvent(oldObject);
90+
return;
91+
}
92+
8693
if (InformerEventSource.this.skipUpdateEventPropagationIfNoChange &&
8794
oldObject.getMetadata().getResourceVersion()
8895
.equals(newObject.getMetadata().getResourceVersion())) {

operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/OperatorExtension.java

+3
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,9 @@ public <T extends HasMetadata> T replace(Class<T> type, T resource) {
140140
return kubernetesClient.resources(type).inNamespace(namespace).replace(resource);
141141
}
142142

143+
public <T extends HasMetadata> boolean delete(Class<T> type, T resource) {
144+
return kubernetesClient.resources(type).inNamespace(namespace).delete(resource);
145+
}
143146

144147
@SuppressWarnings("unchecked")
145148
protected void before(ExtensionContext context) {

operator-framework/src/test/java/io/javaoperatorsdk/operator/InformerEventSourceIT.java

+22-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
import io.javaoperatorsdk.operator.sample.informereventsource.InformerEventSourceTestCustomReconciler;
1414
import io.javaoperatorsdk.operator.sample.informereventsource.InformerEventSourceTestCustomResource;
1515

16-
import static io.javaoperatorsdk.operator.sample.informereventsource.InformerEventSourceTestCustomReconciler.RELATED_RESOURCE_NAME;
17-
import static io.javaoperatorsdk.operator.sample.informereventsource.InformerEventSourceTestCustomReconciler.TARGET_CONFIG_MAP_KEY;
16+
import static io.javaoperatorsdk.operator.sample.informereventsource.InformerEventSourceTestCustomReconciler.*;
1817
import static org.assertj.core.api.Assertions.assertThat;
18+
import static org.assertj.core.api.Assertions.fail;
1919
import static org.awaitility.Awaitility.await;
2020

2121
public class InformerEventSourceIT {
@@ -32,7 +32,7 @@ public class InformerEventSourceIT {
3232
.build();
3333

3434
@Test
35-
public void testUsingInformerToWatchChangesOfConfigMap() {
35+
void testUsingInformerToWatchChangesOfConfigMap() {
3636
var customResource = initialCustomResource();
3737
customResource = operator.create(InformerEventSourceTestCustomResource.class, customResource);
3838
ConfigMap configMap =
@@ -45,6 +45,25 @@ public void testUsingInformerToWatchChangesOfConfigMap() {
4545
waitForCRStatusValue(UPDATE_STATUS_MESSAGE);
4646
}
4747

48+
@Test
49+
void deletingSecondaryResource() {
50+
var customResource = initialCustomResource();
51+
customResource = operator.create(InformerEventSourceTestCustomResource.class, customResource);
52+
ConfigMap configMap =
53+
operator.create(ConfigMap.class, relatedConfigMap(customResource.getMetadata().getName()));
54+
waitForCRStatusValue(INITIAL_STATUS_MESSAGE);
55+
56+
boolean res = operator.delete(ConfigMap.class, configMap);
57+
if (!res) {
58+
fail("Unable to delete configmap");
59+
}
60+
61+
waitForCRStatusValue(MISSING_CONFIG_MAP);
62+
assertThat(((InformerEventSourceTestCustomReconciler) operator.getReconcilers().get(0))
63+
.getNumberOfExecutions())
64+
.isEqualTo(3);
65+
}
66+
4867
private ConfigMap relatedConfigMap(String relatedResourceAnnotation) {
4968
ConfigMap configMap = new ConfigMap();
5069

operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java

+18-6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.javaoperatorsdk.operator.sample.informereventsource;
22

33
import java.util.List;
4+
import java.util.Optional;
5+
import java.util.concurrent.atomic.AtomicInteger;
46

57
import org.slf4j.Logger;
68
import org.slf4j.LoggerFactory;
@@ -34,8 +36,10 @@ public class InformerEventSourceTestCustomReconciler implements
3436

3537
public static final String RELATED_RESOURCE_NAME = "relatedResourceName";
3638
public static final String TARGET_CONFIG_MAP_KEY = "targetStatus";
39+
public static final String MISSING_CONFIG_MAP = "Missing Config Map";
3740

3841
private KubernetesClient kubernetesClient;
42+
private final AtomicInteger numberOfExecutions = new AtomicInteger(0);
3943

4044
@Override
4145
public List<EventSource> prepareEventSources(
@@ -48,16 +52,20 @@ public List<EventSource> prepareEventSources(
4852
public UpdateControl<InformerEventSourceTestCustomResource> reconcile(
4953
InformerEventSourceTestCustomResource resource,
5054
Context context) {
55+
numberOfExecutions.incrementAndGet();
5156

57+
resource.setStatus(new InformerEventSourceTestCustomResourceStatus());
5258
// Reading the config map from the informer not from the API
5359
// name of the config map same as custom resource for sake of simplicity
54-
ConfigMap configMap = context.getSecondaryResource(ConfigMap.class)
55-
.orElseThrow(() -> new IllegalStateException("Config map should be present."));
60+
Optional<ConfigMap> configMap = context.getSecondaryResource(ConfigMap.class);
61+
if (configMap.isEmpty()) {
62+
resource.getStatus().setConfigMapValue(MISSING_CONFIG_MAP);
63+
} else {
64+
String targetStatus = configMap.get().getData().get(TARGET_CONFIG_MAP_KEY);
65+
LOGGER.debug("Setting target status for CR: {}", targetStatus);
66+
resource.getStatus().setConfigMapValue(targetStatus);
67+
}
5668

57-
String targetStatus = configMap.getData().get(TARGET_CONFIG_MAP_KEY);
58-
LOGGER.debug("Setting target status for CR: {}", targetStatus);
59-
resource.setStatus(new InformerEventSourceTestCustomResourceStatus());
60-
resource.getStatus().setConfigMapValue(targetStatus);
6169
return UpdateControl.updateStatus(resource);
6270
}
6371

@@ -70,4 +78,8 @@ public KubernetesClient getKubernetesClient() {
7078
public void setKubernetesClient(KubernetesClient kubernetesClient) {
7179
this.kubernetesClient = kubernetesClient;
7280
}
81+
82+
public int getNumberOfExecutions() {
83+
return numberOfExecutions.get();
84+
}
7385
}

0 commit comments

Comments
 (0)