Skip to content

feat: make RegisteredController a little more useful #1199

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package io.javaoperatorsdk.operator;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Consumer;

import org.slf4j.Logger;
Expand Down Expand Up @@ -120,10 +124,10 @@ public void stop() throws OperatorException {
* registration of the reconciler is delayed till the operator is started.
*
* @param reconciler the reconciler to register
* @param <R> the {@code CustomResource} type associated with the reconciler
* @param <P> the {@code CustomResource} type associated with the reconciler
* @throws OperatorException if a problem occurred during the registration process
*/
public <R extends HasMetadata> RegisteredController register(Reconciler<R> reconciler)
public <P extends HasMetadata> RegisteredController<P> register(Reconciler<P> reconciler)
throws OperatorException {
final var controllerConfiguration =
ConfigurationServiceProvider.instance().getConfigurationFor(reconciler);
Expand All @@ -139,11 +143,11 @@ public <R extends HasMetadata> RegisteredController register(Reconciler<R> recon
*
* @param reconciler part of the reconciler to register
* @param configuration the configuration with which we want to register the reconciler
* @param <R> the {@code HasMetadata} type associated with the reconciler
* @param <P> the {@code HasMetadata} type associated with the reconciler
* @throws OperatorException if a problem occurred during the registration process
*/
public <R extends HasMetadata> RegisteredController register(Reconciler<R> reconciler,
ControllerConfiguration<R> configuration)
public <P extends HasMetadata> RegisteredController<P> register(Reconciler<P> reconciler,
ControllerConfiguration<P> configuration)
throws OperatorException {

if (configuration == null) {
Expand Down Expand Up @@ -175,17 +179,29 @@ public <R extends HasMetadata> RegisteredController register(Reconciler<R> recon
*
* @param reconciler part of the reconciler to register
* @param configOverrider consumer to use to change config values
* @param <R> the {@code HasMetadata} type associated with the reconciler
* @param <P> the {@code HasMetadata} type associated with the reconciler
*/
public <R extends HasMetadata> RegisteredController register(Reconciler<R> reconciler,
Consumer<ControllerConfigurationOverrider<R>> configOverrider) {
public <P extends HasMetadata> RegisteredController<P> register(Reconciler<P> reconciler,
Consumer<ControllerConfigurationOverrider<P>> configOverrider) {
final var controllerConfiguration =
ConfigurationServiceProvider.instance().getConfigurationFor(reconciler);
var configToOverride = ControllerConfigurationOverrider.override(controllerConfiguration);
configOverrider.accept(configToOverride);
return register(reconciler, configToOverride.build());
}

public Optional<RegisteredController> getRegisteredController(String name) {
return controllers.get(name).map(RegisteredController.class::cast);
}

public Set<RegisteredController> getRegisteredControllers() {
return new HashSet<>(controllers.controllers());
}

public int getRegisteredControllersNumber() {
return controllers.size();
}

static class ControllerManager implements LifecycleAware {
private final Map<String, Controller> controllers = new HashMap<>();
private boolean started = false;
Expand All @@ -200,12 +216,12 @@ public synchronized void shouldStart() {
}

public synchronized void start() {
controllers.values().parallelStream().forEach(Controller::start);
controllers().parallelStream().forEach(Controller::start);
started = true;
}

public synchronized void stop() {
this.controllers.values().parallelStream().forEach(closeable -> {
controllers().parallelStream().forEach(closeable -> {
log.debug("closing {}", closeable);
closeable.stop();
});
Expand All @@ -224,10 +240,24 @@ synchronized void add(Controller controller) {
+ "': another controller named '" + existing.getConfiguration().getName()
+ "' is already registered for resource '" + resourceTypeName + "'");
}
this.controllers.put(resourceTypeName, controller);
controllers.put(resourceTypeName, controller);
if (started) {
controller.start();
}
}

synchronized Optional<Controller> get(String name) {
return controllers().stream()
.filter(c -> name.equals(c.getConfiguration().getName()))
.findFirst();
}

synchronized Collection<Controller> controllers() {
return controllers.values();
}

synchronized int size() {
return controllers.size();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package io.javaoperatorsdk.operator;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
import io.javaoperatorsdk.operator.api.config.NamespaceChangeable;

public interface RegisteredController extends NamespaceChangeable {
public interface RegisteredController<P extends HasMetadata> extends NamespaceChangeable {
ControllerConfiguration<P> getConfiguration();
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
@SuppressWarnings({"unchecked", "rawtypes"})
@Ignore
public class Controller<P extends HasMetadata>
implements Reconciler<P>, Cleaner<P>, LifecycleAware, RegisteredController {
implements Reconciler<P>, Cleaner<P>, LifecycleAware, RegisteredController<P> {

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

Expand All @@ -11,32 +12,69 @@
import io.javaoperatorsdk.operator.api.config.AbstractConfigurationService;
import io.javaoperatorsdk.operator.api.config.ConfigurationServiceProvider;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

@SuppressWarnings("rawtypes")
class OperatorTest {

private final KubernetesClient kubernetesClient = MockKubernetesClient.client(ConfigMap.class);
private final Operator operator = new Operator(kubernetesClient);
private final FooReconciler fooReconciler = new FooReconciler();
private Operator operator;

@BeforeAll
@AfterAll
static void setUpConfigurationServiceProvider() {
ConfigurationServiceProvider.reset();
}

@BeforeEach
void initOperator() {
ConfigurationServiceProvider.reset();
operator = new Operator(kubernetesClient);
}

@Test
@DisplayName("should throw `OperationException` when Configuration is null")
public void shouldThrowOperatorExceptionWhenConfigurationIsNull() {
// use a ConfigurationService that doesn't automatically create configurations
ConfigurationServiceProvider.reset();
ConfigurationServiceProvider.set(new AbstractConfigurationService(null));

Assertions.assertThrows(OperatorException.class, () -> operator.register(fooReconciler));
Assertions.assertThrows(OperatorException.class, () -> operator.register(new FooReconciler()));
}

@Test
void shouldBePossibleToRetrieveNumberOfRegisteredControllers() {
assertEquals(0, operator.getRegisteredControllersNumber());

operator.register(new FooReconciler());
assertEquals(1, operator.getRegisteredControllersNumber());
}

@Test
void shouldBePossibleToRetrieveRegisteredControllerByName() {
final var reconciler = new FooReconciler();
final var name = ReconcilerUtils.getNameFor(reconciler);

var registeredControllers = operator.getRegisteredControllers();
assertTrue(operator.getRegisteredController(name).isEmpty());
assertTrue(registeredControllers.isEmpty());

operator.register(reconciler);
final var maybeController = operator.getRegisteredController(name);
assertTrue(maybeController.isPresent());
assertEquals(name, maybeController.map(rc -> rc.getConfiguration().getName()).orElseThrow());

registeredControllers = operator.getRegisteredControllers();
assertEquals(1, registeredControllers.size());
assertEquals(maybeController.get(), registeredControllers.stream().findFirst().orElseThrow());
}

@ControllerConfiguration
private static class FooReconciler implements Reconciler<ConfigMap> {

@Override
Expand Down