Skip to content

Commit 5280d26

Browse files
authored
Merge branch 'main' into next
2 parents 6839b63 + 28aa164 commit 5280d26

File tree

9 files changed

+175
-8
lines changed

9 files changed

+175
-8
lines changed

Diff for: docs/documentation/dependent-resources.md

-5
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@ permalink: /docs/dependent-resources
77

88
# Dependent Resources
99

10-
DISCLAIMER: The Dependent Resource support is a relatively new feature, while we strove to cover
11-
what we anticipate will be the most common use cases, the implementation is not simple and might
12-
still evolve. As a result, some APIs could be a subject of change in the future. However,
13-
non-backwards compatible changes are expected to be trivial to migrate to.
14-
1510
## Motivations and Goals
1611

1712
Most operators need to deal with secondary resources when trying to realize the desired state

Diff for: operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventProcessor.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,12 @@ private void submitReconciliationExecution(ResourceState state) {
146146
controllerUnderExecution,
147147
maybeLatest.isPresent());
148148
if (maybeLatest.isEmpty()) {
149-
log.debug("no custom resource found in cache for resource id: {}", resourceID);
149+
// there can be multiple reasons why the primary resource is not present, one is that the
150+
// informer is currently disconnected from k8s api server, but will eventually receive the
151+
// resource. Other is that simply there is no primary resource present for an event, this
152+
// might indicate issue with the implementation, but could happen also naturally, thus
153+
// this is not necessarily a problem.
154+
log.debug("no primary resource found in cache with resource id: {}", resourceID);
150155
}
151156
}
152157
} finally {

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ public void setConfigurationService(ConfigurationService configurationService) {
300300
super.setConfigurationService(configurationService);
301301

302302
cache.addIndexers(indexerBuffer);
303-
indexerBuffer = null;
303+
indexerBuffer = new HashMap<>();
304304
}
305305

306306
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package io.javaoperatorsdk.operator;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import io.fabric8.kubernetes.client.KubernetesClient;
6+
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
7+
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
8+
import io.javaoperatorsdk.operator.sample.dependentreinitialization.ConfigMapDependentResource;
9+
import io.javaoperatorsdk.operator.sample.dependentreinitialization.DependentReInitializationCustomResource;
10+
import io.javaoperatorsdk.operator.sample.dependentreinitialization.DependentReInitializationReconciler;
11+
12+
class DependentReInitializationIT {
13+
14+
/**
15+
* In case dependent resource is managed by CDI (like in Quarkus) can be handy that the instance
16+
* is reused in tests.
17+
*/
18+
@Test
19+
void dependentCanDeReInitialized() {
20+
var client = new KubernetesClientBuilder().build();
21+
LocallyRunOperatorExtension.applyCrd(DependentReInitializationCustomResource.class, client);
22+
23+
var dependent = new ConfigMapDependentResource();
24+
25+
startEndStopOperator(client, dependent);
26+
startEndStopOperator(client, dependent);
27+
}
28+
29+
private static void startEndStopOperator(KubernetesClient client,
30+
ConfigMapDependentResource dependent) {
31+
Operator o1 = new Operator(o -> o
32+
.withCloseClientOnStop(false)
33+
.withKubernetesClient(client));
34+
o1.register(new DependentReInitializationReconciler(dependent, client));
35+
o1.start();
36+
o1.stop();
37+
}
38+
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package io.javaoperatorsdk.operator;
2+
3+
import java.time.Duration;
4+
5+
import org.junit.jupiter.api.Test;
6+
import org.junit.jupiter.api.Timeout;
7+
8+
import io.fabric8.kubernetes.api.model.ConfigMap;
9+
import io.fabric8.kubernetes.client.ConfigBuilder;
10+
import io.fabric8.kubernetes.client.KubernetesClient;
11+
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
12+
import io.javaoperatorsdk.operator.api.reconciler.Context;
13+
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
14+
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
15+
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
16+
17+
class InformerErrorHandlerStartIT {
18+
/**
19+
* Test showcases that the operator starts even if there is no access right for some resource.
20+
*/
21+
@Test
22+
@Timeout(5)
23+
void operatorStart() {
24+
KubernetesClient client = new KubernetesClientBuilder()
25+
.withConfig(new ConfigBuilder()
26+
.withImpersonateUsername("user-with-no-rights")
27+
.build())
28+
.build();
29+
30+
Operator operator = new Operator(o -> o
31+
.withKubernetesClient(client)
32+
.withStopOnInformerErrorDuringStartup(false)
33+
.withCacheSyncTimeout(Duration.ofSeconds(2)));
34+
operator.register(new ConfigMapReconciler());
35+
operator.start();
36+
}
37+
38+
@ControllerConfiguration
39+
public static class ConfigMapReconciler implements Reconciler<ConfigMap> {
40+
@Override
41+
public UpdateControl<ConfigMap> reconcile(ConfigMap resource, Context<ConfigMap> context)
42+
throws Exception {
43+
return UpdateControl.noUpdate();
44+
}
45+
}
46+
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.javaoperatorsdk.operator.sample.dependentreinitialization;
2+
3+
import java.util.Map;
4+
5+
import io.fabric8.kubernetes.api.model.ConfigMap;
6+
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
7+
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
8+
import io.javaoperatorsdk.operator.api.reconciler.Context;
9+
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
10+
11+
public class ConfigMapDependentResource
12+
extends CRUDKubernetesDependentResource<ConfigMap, DependentReInitializationCustomResource> {
13+
14+
public ConfigMapDependentResource() {
15+
super(ConfigMap.class);
16+
}
17+
18+
@Override
19+
protected ConfigMap desired(DependentReInitializationCustomResource primary,
20+
Context<DependentReInitializationCustomResource> context) {
21+
return new ConfigMapBuilder()
22+
.withMetadata(new ObjectMetaBuilder()
23+
.withName(primary.getMetadata().getName())
24+
.withNamespace(primary.getMetadata().getNamespace())
25+
.build())
26+
.withData(Map.of("key", "val"))
27+
.build();
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package io.javaoperatorsdk.operator.sample.dependentreinitialization;
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.Version;
7+
8+
@Group("sample.javaoperatorsdk")
9+
@Version("v1")
10+
public class DependentReInitializationCustomResource
11+
extends CustomResource<Void, Void>
12+
implements Namespaced {
13+
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package io.javaoperatorsdk.operator.sample.dependentreinitialization;
2+
3+
import java.util.Map;
4+
5+
import io.fabric8.kubernetes.client.KubernetesClient;
6+
import io.javaoperatorsdk.operator.api.reconciler.*;
7+
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
8+
9+
@ControllerConfiguration
10+
public class DependentReInitializationReconciler
11+
implements Reconciler<DependentReInitializationCustomResource>,
12+
EventSourceInitializer<DependentReInitializationCustomResource> {
13+
14+
private final ConfigMapDependentResource configMapDependentResource;
15+
16+
public DependentReInitializationReconciler(ConfigMapDependentResource dependentResource,
17+
KubernetesClient client) {
18+
this.configMapDependentResource = dependentResource;
19+
this.configMapDependentResource.setKubernetesClient(client);
20+
}
21+
22+
@Override
23+
public UpdateControl<DependentReInitializationCustomResource> reconcile(
24+
DependentReInitializationCustomResource resource,
25+
Context<DependentReInitializationCustomResource> context) throws Exception {
26+
configMapDependentResource.reconcile(resource, context);
27+
return UpdateControl.noUpdate();
28+
}
29+
30+
@Override
31+
public Map<String, EventSource> prepareEventSources(
32+
EventSourceContext<DependentReInitializationCustomResource> context) {
33+
return EventSourceInitializer.nameEventSourcesFromDependentResource(context,
34+
configMapDependentResource);
35+
}
36+
37+
38+
}

Diff for: pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
<fabric8-client.version>6.7.2</fabric8-client.version>
4848
<slf4j.version>1.7.36</slf4j.version>
4949
<log4j.version>2.20.0</log4j.version>
50-
<mokito.version>5.4.0</mokito.version>
50+
<mokito.version>5.5.0</mokito.version>
5151
<commons-lang3.version>3.13.0</commons-lang3.version>
5252
<compile-testing.version>0.19</compile-testing.version>
5353
<javapoet.version>1.13.0</javapoet.version>

0 commit comments

Comments
 (0)