Skip to content

Commit 2941884

Browse files
authored
feat: make RegisteredController a little more useful (#1199)
Allows to retrieve information from registered controllers from Operator, in particular if there are any registered controllers, which the Quarkus extension uses to determine whether or not to start the Operator.
1 parent e456260 commit 2941884

File tree

4 files changed

+87
-16
lines changed

4 files changed

+87
-16
lines changed

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/Operator.java

+41-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package io.javaoperatorsdk.operator;
22

3+
import java.util.Collection;
34
import java.util.HashMap;
5+
import java.util.HashSet;
46
import java.util.Map;
7+
import java.util.Optional;
8+
import java.util.Set;
59
import java.util.function.Consumer;
610

711
import org.slf4j.Logger;
@@ -120,10 +124,10 @@ public void stop() throws OperatorException {
120124
* registration of the reconciler is delayed till the operator is started.
121125
*
122126
* @param reconciler the reconciler to register
123-
* @param <R> the {@code CustomResource} type associated with the reconciler
127+
* @param <P> the {@code CustomResource} type associated with the reconciler
124128
* @throws OperatorException if a problem occurred during the registration process
125129
*/
126-
public <R extends HasMetadata> RegisteredController register(Reconciler<R> reconciler)
130+
public <P extends HasMetadata> RegisteredController<P> register(Reconciler<P> reconciler)
127131
throws OperatorException {
128132
final var controllerConfiguration =
129133
ConfigurationServiceProvider.instance().getConfigurationFor(reconciler);
@@ -139,11 +143,11 @@ public <R extends HasMetadata> RegisteredController register(Reconciler<R> recon
139143
*
140144
* @param reconciler part of the reconciler to register
141145
* @param configuration the configuration with which we want to register the reconciler
142-
* @param <R> the {@code HasMetadata} type associated with the reconciler
146+
* @param <P> the {@code HasMetadata} type associated with the reconciler
143147
* @throws OperatorException if a problem occurred during the registration process
144148
*/
145-
public <R extends HasMetadata> RegisteredController register(Reconciler<R> reconciler,
146-
ControllerConfiguration<R> configuration)
149+
public <P extends HasMetadata> RegisteredController<P> register(Reconciler<P> reconciler,
150+
ControllerConfiguration<P> configuration)
147151
throws OperatorException {
148152

149153
if (configuration == null) {
@@ -175,17 +179,29 @@ public <R extends HasMetadata> RegisteredController register(Reconciler<R> recon
175179
*
176180
* @param reconciler part of the reconciler to register
177181
* @param configOverrider consumer to use to change config values
178-
* @param <R> the {@code HasMetadata} type associated with the reconciler
182+
* @param <P> the {@code HasMetadata} type associated with the reconciler
179183
*/
180-
public <R extends HasMetadata> RegisteredController register(Reconciler<R> reconciler,
181-
Consumer<ControllerConfigurationOverrider<R>> configOverrider) {
184+
public <P extends HasMetadata> RegisteredController<P> register(Reconciler<P> reconciler,
185+
Consumer<ControllerConfigurationOverrider<P>> configOverrider) {
182186
final var controllerConfiguration =
183187
ConfigurationServiceProvider.instance().getConfigurationFor(reconciler);
184188
var configToOverride = ControllerConfigurationOverrider.override(controllerConfiguration);
185189
configOverrider.accept(configToOverride);
186190
return register(reconciler, configToOverride.build());
187191
}
188192

193+
public Optional<RegisteredController> getRegisteredController(String name) {
194+
return controllers.get(name).map(RegisteredController.class::cast);
195+
}
196+
197+
public Set<RegisteredController> getRegisteredControllers() {
198+
return new HashSet<>(controllers.controllers());
199+
}
200+
201+
public int getRegisteredControllersNumber() {
202+
return controllers.size();
203+
}
204+
189205
static class ControllerManager implements LifecycleAware {
190206
private final Map<String, Controller> controllers = new HashMap<>();
191207
private boolean started = false;
@@ -200,12 +216,12 @@ public synchronized void shouldStart() {
200216
}
201217

202218
public synchronized void start() {
203-
controllers.values().parallelStream().forEach(Controller::start);
219+
controllers().parallelStream().forEach(Controller::start);
204220
started = true;
205221
}
206222

207223
public synchronized void stop() {
208-
this.controllers.values().parallelStream().forEach(closeable -> {
224+
controllers().parallelStream().forEach(closeable -> {
209225
log.debug("closing {}", closeable);
210226
closeable.stop();
211227
});
@@ -224,10 +240,24 @@ synchronized void add(Controller controller) {
224240
+ "': another controller named '" + existing.getConfiguration().getName()
225241
+ "' is already registered for resource '" + resourceTypeName + "'");
226242
}
227-
this.controllers.put(resourceTypeName, controller);
243+
controllers.put(resourceTypeName, controller);
228244
if (started) {
229245
controller.start();
230246
}
231247
}
248+
249+
synchronized Optional<Controller> get(String name) {
250+
return controllers().stream()
251+
.filter(c -> name.equals(c.getConfiguration().getName()))
252+
.findFirst();
253+
}
254+
255+
synchronized Collection<Controller> controllers() {
256+
return controllers.values();
257+
}
258+
259+
synchronized int size() {
260+
return controllers.size();
261+
}
232262
}
233263
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package io.javaoperatorsdk.operator;
22

3+
import io.fabric8.kubernetes.api.model.HasMetadata;
4+
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
35
import io.javaoperatorsdk.operator.api.config.NamespaceChangeable;
46

5-
public interface RegisteredController extends NamespaceChangeable {
7+
public interface RegisteredController<P extends HasMetadata> extends NamespaceChangeable {
8+
ControllerConfiguration<P> getConfiguration();
69
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
@SuppressWarnings({"unchecked", "rawtypes"})
3434
@Ignore
3535
public class Controller<P extends HasMetadata>
36-
implements Reconciler<P>, Cleaner<P>, LifecycleAware, RegisteredController {
36+
implements Reconciler<P>, Cleaner<P>, LifecycleAware, RegisteredController<P> {
3737

3838
private static final Logger log = LoggerFactory.getLogger(Controller.class);
3939

operator-framework-core/src/test/java/io/javaoperatorsdk/operator/OperatorTest.java

+41-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.junit.jupiter.api.AfterAll;
44
import org.junit.jupiter.api.Assertions;
55
import org.junit.jupiter.api.BeforeAll;
6+
import org.junit.jupiter.api.BeforeEach;
67
import org.junit.jupiter.api.DisplayName;
78
import org.junit.jupiter.api.Test;
89

@@ -11,32 +12,69 @@
1112
import io.javaoperatorsdk.operator.api.config.AbstractConfigurationService;
1213
import io.javaoperatorsdk.operator.api.config.ConfigurationServiceProvider;
1314
import io.javaoperatorsdk.operator.api.reconciler.Context;
15+
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
1416
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
1517
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
1618

19+
import static org.junit.jupiter.api.Assertions.assertEquals;
20+
import static org.junit.jupiter.api.Assertions.assertTrue;
21+
1722
@SuppressWarnings("rawtypes")
1823
class OperatorTest {
1924

2025
private final KubernetesClient kubernetesClient = MockKubernetesClient.client(ConfigMap.class);
21-
private final Operator operator = new Operator(kubernetesClient);
22-
private final FooReconciler fooReconciler = new FooReconciler();
26+
private Operator operator;
2327

2428
@BeforeAll
2529
@AfterAll
2630
static void setUpConfigurationServiceProvider() {
2731
ConfigurationServiceProvider.reset();
2832
}
2933

34+
@BeforeEach
35+
void initOperator() {
36+
ConfigurationServiceProvider.reset();
37+
operator = new Operator(kubernetesClient);
38+
}
39+
3040
@Test
3141
@DisplayName("should throw `OperationException` when Configuration is null")
3242
public void shouldThrowOperatorExceptionWhenConfigurationIsNull() {
3343
// use a ConfigurationService that doesn't automatically create configurations
3444
ConfigurationServiceProvider.reset();
3545
ConfigurationServiceProvider.set(new AbstractConfigurationService(null));
3646

37-
Assertions.assertThrows(OperatorException.class, () -> operator.register(fooReconciler));
47+
Assertions.assertThrows(OperatorException.class, () -> operator.register(new FooReconciler()));
48+
}
49+
50+
@Test
51+
void shouldBePossibleToRetrieveNumberOfRegisteredControllers() {
52+
assertEquals(0, operator.getRegisteredControllersNumber());
53+
54+
operator.register(new FooReconciler());
55+
assertEquals(1, operator.getRegisteredControllersNumber());
56+
}
57+
58+
@Test
59+
void shouldBePossibleToRetrieveRegisteredControllerByName() {
60+
final var reconciler = new FooReconciler();
61+
final var name = ReconcilerUtils.getNameFor(reconciler);
62+
63+
var registeredControllers = operator.getRegisteredControllers();
64+
assertTrue(operator.getRegisteredController(name).isEmpty());
65+
assertTrue(registeredControllers.isEmpty());
66+
67+
operator.register(reconciler);
68+
final var maybeController = operator.getRegisteredController(name);
69+
assertTrue(maybeController.isPresent());
70+
assertEquals(name, maybeController.map(rc -> rc.getConfiguration().getName()).orElseThrow());
71+
72+
registeredControllers = operator.getRegisteredControllers();
73+
assertEquals(1, registeredControllers.size());
74+
assertEquals(maybeController.get(), registeredControllers.stream().findFirst().orElseThrow());
3875
}
3976

77+
@ControllerConfiguration
4078
private static class FooReconciler implements Reconciler<ConfigMap> {
4179

4280
@Override

0 commit comments

Comments
 (0)