diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java index 150af208bd..f13ae118f8 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java @@ -9,6 +9,7 @@ import io.fabric8.kubernetes.client.CustomResource; import io.javaoperatorsdk.operator.api.monitoring.Metrics; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceFactory; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -19,6 +20,7 @@ public interface ConfigurationService { ObjectMapper OBJECT_MAPPER = new ObjectMapper(); Cloner DEFAULT_CLONER = new Cloner() { + @SuppressWarnings("unchecked") @Override public HasMetadata clone(HasMetadata object) { try { @@ -126,4 +128,8 @@ default boolean closeClientOnStop() { default ObjectMapper getObjectMapper() { return OBJECT_MAPPER; } + + default DependentResourceFactory dependentResourceFactory() { + return new DependentResourceFactory() {}; + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java index 0a750d836c..799355185c 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/AbstractDependentResource.java @@ -125,6 +125,7 @@ private RecentOperationCacheFiller eventSourceAsRecentOperationCacheFiller() return (RecentOperationCacheFiller) ((EventSourceProvider

) this).getEventSource(); } + @SuppressWarnings("unchecked") // this cannot be done in constructor since event source might be initialized later protected boolean isFilteringEventSource() { if (this instanceof EventSourceProvider) { @@ -135,6 +136,7 @@ protected boolean isFilteringEventSource() { } } + @SuppressWarnings("unchecked") // this cannot be done in constructor since event source might be initialized later protected boolean isRecentOperationCacheFiller() { if (this instanceof EventSourceProvider) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceFactory.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceFactory.java new file mode 100644 index 0000000000..ffd0ba496f --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResourceFactory.java @@ -0,0 +1,19 @@ +package io.javaoperatorsdk.operator.api.reconciler.dependent; + +import java.lang.reflect.InvocationTargetException; + +import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec; + +public interface DependentResourceFactory { + + default > T createFrom(DependentResourceSpec spec) { + try { + return spec.getDependentResourceClass().getConstructor().newInstance(); + } catch (InstantiationException | NoSuchMethodException | IllegalAccessException + | InvocationTargetException e) { + throw new IllegalArgumentException("Cannot instantiate DependentResource " + + spec.getDependentResourceClass().getCanonicalName(), e); + } + } + +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/ResourceTypeAware.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/ResourceTypeAware.java new file mode 100644 index 0000000000..e83d39aebd --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/ResourceTypeAware.java @@ -0,0 +1,6 @@ +package io.javaoperatorsdk.operator.api.reconciler.dependent; + +public interface ResourceTypeAware { + + Class resourceType(); +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java index 5fc1b9ede7..de71d54171 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java @@ -2,6 +2,7 @@ import java.util.LinkedList; import java.util.List; +import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,9 +19,11 @@ import io.javaoperatorsdk.operator.OperatorException; import io.javaoperatorsdk.operator.api.config.ConfigurationServiceProvider; import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec; import io.javaoperatorsdk.operator.api.monitoring.Metrics; import io.javaoperatorsdk.operator.api.monitoring.Metrics.ControllerExecution; import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.ContextInitializer; import io.javaoperatorsdk.operator.api.reconciler.DeleteControl; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer; @@ -28,11 +31,13 @@ import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; -import io.javaoperatorsdk.operator.processing.dependent.DependentResourceManager; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceConfigurator; +import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.EventSourceManager; import io.javaoperatorsdk.operator.processing.event.source.EventSource; -@SuppressWarnings({"unchecked"}) +@SuppressWarnings({"unchecked", "rawtypes"}) @Ignore public class Controller

implements Reconciler

, LifecycleAware, EventSourceInitializer

{ @@ -43,7 +48,8 @@ public class Controller

implements Reconciler

, private final ControllerConfiguration

configuration; private final KubernetesClient kubernetesClient; private final EventSourceManager

eventSourceManager; - private final DependentResourceManager

dependents; + private final List dependents; + private final boolean contextInitializer; public Controller(Reconciler

reconciler, ControllerConfiguration

configuration, @@ -51,14 +57,42 @@ public Controller(Reconciler

reconciler, this.reconciler = reconciler; this.configuration = configuration; this.kubernetesClient = kubernetesClient; + contextInitializer = reconciler instanceof ContextInitializer; eventSourceManager = new EventSourceManager<>(this); - dependents = new DependentResourceManager<>(this); + + dependents = configuration.getDependentResources().stream() + .map(drs -> createAndConfigureFrom(drs, kubernetesClient)) + .collect(Collectors.toList()); + } + + @SuppressWarnings("rawtypes") + private DependentResource createAndConfigureFrom(DependentResourceSpec spec, + KubernetesClient client) { + final var dependentResource = + ConfigurationServiceProvider.instance().dependentResourceFactory().createFrom(spec); + + if (dependentResource instanceof KubernetesClientAware) { + ((KubernetesClientAware) dependentResource).setKubernetesClient(client); + } + + if (dependentResource instanceof DependentResourceConfigurator) { + final var configurator = (DependentResourceConfigurator) dependentResource; + spec.getDependentResourceConfiguration().ifPresent(configurator::configureWith); + } + return dependentResource; + } + + private void initContextIfNeeded(P resource, Context

context) { + if (contextInitializer) { + ((ContextInitializer

) reconciler).initContext(resource, context); + } } @Override public DeleteControl cleanup(P resource, Context

context) { - dependents.cleanup(resource, context); + initContextIfNeeded(resource, context); + dependents.forEach(dependent -> dependent.cleanup(resource, context)); try { return metrics().timeControllerExecution( @@ -90,7 +124,8 @@ public DeleteControl execute() { @Override public UpdateControl

reconcile(P resource, Context

context) throws Exception { - dependents.reconcile(resource, context); + initContextIfNeeded(resource, context); + dependents.forEach(dependent -> dependent.reconcile(resource, context)); return metrics().timeControllerExecution( new ControllerExecution<>() { @@ -131,8 +166,12 @@ private Metrics metrics() { @Override public List prepareEventSources(EventSourceContext

context) { - final var dependentSources = dependents.prepareEventSources(context); - List sources = new LinkedList<>(dependentSources); + List sources = new LinkedList<>(); + dependents.stream() + .filter(dependentResource -> dependentResource instanceof EventSourceProvider) + .map(EventSourceProvider.class::cast) + .map(provider -> provider.initEventSource(context)) + .forEach(sources::add); // add manually defined event sources if (reconciler instanceof EventSourceInitializer) { @@ -267,6 +306,6 @@ public void stop() { @SuppressWarnings("rawtypes") public List getDependents() { - return dependents.getDependents(); + return dependents; } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java deleted file mode 100644 index 3dd3a2860e..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceManager.java +++ /dev/null @@ -1,112 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent; - -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.client.KubernetesClient; -import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; -import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec; -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.ContextInitializer; -import io.javaoperatorsdk.operator.api.reconciler.DeleteControl; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer; -import io.javaoperatorsdk.operator.api.reconciler.Ignore; -import io.javaoperatorsdk.operator.api.reconciler.Reconciler; -import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; -import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; -import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceConfigurator; -import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider; -import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesClientAware; -import io.javaoperatorsdk.operator.processing.Controller; -import io.javaoperatorsdk.operator.processing.event.source.EventSource; - -@SuppressWarnings({"rawtypes", "unchecked"}) -@Ignore -public class DependentResourceManager

- implements EventSourceInitializer

, Reconciler

{ - - private static final Logger log = LoggerFactory.getLogger(DependentResourceManager.class); - - private final Reconciler

reconciler; - private final ControllerConfiguration

controllerConfiguration; - private List dependents; - - public DependentResourceManager(Controller

controller) { - this.reconciler = controller.getReconciler(); - this.controllerConfiguration = controller.getConfiguration(); - } - - @Override - public List prepareEventSources(EventSourceContext

context) { - final var dependentResources = controllerConfiguration.getDependentResources(); - final var sources = new ArrayList(dependentResources.size()); - dependents = - dependentResources.stream() - .map( - drc -> { - final var dependentResource = createAndConfigureFrom(drc, context.getClient()); - if (dependentResource instanceof EventSourceProvider) { - EventSourceProvider provider = (EventSourceProvider) dependentResource; - sources.add(provider.initEventSource(context)); - } - return dependentResource; - }) - .collect(Collectors.toList()); - return sources; - } - - @Override - public UpdateControl

reconcile(P resource, Context

context) { - initContextIfNeeded(resource, context); - dependents.forEach(dependent -> dependent.reconcile(resource, context)); - return UpdateControl.noUpdate(); - } - - @Override - public DeleteControl cleanup(P resource, Context

context) { - initContextIfNeeded(resource, context); - dependents.forEach(dependent -> dependent.cleanup(resource, context)); - return Reconciler.super.cleanup(resource, context); - } - - private void initContextIfNeeded(P resource, Context context) { - if (reconciler instanceof ContextInitializer) { - final var initializer = (ContextInitializer

) reconciler; - initializer.initContext(resource, context); - } - } - - private DependentResource createAndConfigureFrom(DependentResourceSpec dependentResourceSpec, - KubernetesClient client) { - try { - DependentResource dependentResource = - (DependentResource) dependentResourceSpec.getDependentResourceClass() - .getConstructor().newInstance(); - - if (dependentResource instanceof KubernetesClientAware) { - ((KubernetesClientAware) dependentResource).setKubernetesClient(client); - } - - if (dependentResource instanceof DependentResourceConfigurator) { - final var configurator = (DependentResourceConfigurator) dependentResource; - dependentResourceSpec.getDependentResourceConfiguration() - .ifPresent(configurator::configureWith); - } - return dependentResource; - } catch (InstantiationException | NoSuchMethodException | IllegalAccessException - | InvocationTargetException e) { - throw new IllegalStateException(e); - } - } - - public List getDependents() { - return dependents; - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractCachingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractCachingDependentResource.java index 86f2c23d54..04b49bf0bf 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractCachingDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractCachingDependentResource.java @@ -3,16 +3,22 @@ import java.util.Optional; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.config.Utils; import io.javaoperatorsdk.operator.api.reconciler.dependent.AbstractDependentResource; import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider; +import io.javaoperatorsdk.operator.api.reconciler.dependent.ResourceTypeAware; import io.javaoperatorsdk.operator.processing.event.ExternalResourceCachingEventSource; import io.javaoperatorsdk.operator.processing.event.source.EventSource; public abstract class AbstractCachingDependentResource - extends AbstractDependentResource implements EventSourceProvider

{ + extends AbstractDependentResource + implements EventSourceProvider

, ResourceTypeAware { protected ExternalResourceCachingEventSource eventSource; + private final Class resourceType; + + protected AbstractCachingDependentResource(Class resourceType) { + this.resourceType = resourceType; + } public Optional fetchResource(P primaryResource) { return eventSource.getAssociated(primaryResource); @@ -23,8 +29,9 @@ public EventSource getEventSource() { return eventSource; } - protected Class resourceType() { - return (Class) Utils.getFirstTypeArgumentFromExtendedClass(getClass()); + @Override + public Class resourceType() { + return resourceType; } @Override diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractPollingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractPollingDependentResource.java new file mode 100644 index 0000000000..8c91dea15d --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/AbstractPollingDependentResource.java @@ -0,0 +1,27 @@ +package io.javaoperatorsdk.operator.processing.dependent.external; + +import io.fabric8.kubernetes.api.model.HasMetadata; + +public abstract class AbstractPollingDependentResource + extends AbstractCachingDependentResource { + + public static final int DEFAULT_POLLING_PERIOD = 5000; + private long pollingPeriod; + + protected AbstractPollingDependentResource(Class resourceType) { + this(resourceType, DEFAULT_POLLING_PERIOD); + } + + public AbstractPollingDependentResource(Class resourceType, long pollingPeriod) { + super(resourceType); + this.pollingPeriod = pollingPeriod; + } + + public void setPollingPeriod(long pollingPeriod) { + this.pollingPeriod = pollingPeriod; + } + + public long getPollingPeriod() { + return pollingPeriod; + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java index c5f9e2c888..11b18832a7 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PerResourcePollingDependentResource.java @@ -5,36 +5,21 @@ import io.javaoperatorsdk.operator.processing.event.source.EventSource; import io.javaoperatorsdk.operator.processing.event.source.polling.PerResourcePollingEventSource; -import static io.javaoperatorsdk.operator.processing.dependent.external.PollingDependentResource.DEFAULT_POLLING_PERIOD; - public abstract class PerResourcePollingDependentResource - extends AbstractCachingDependentResource + extends AbstractPollingDependentResource implements PerResourcePollingEventSource.ResourceFetcher { - - protected long pollingPeriod; - - public PerResourcePollingDependentResource() { - this(DEFAULT_POLLING_PERIOD); + public PerResourcePollingDependentResource(Class resourceType) { + super(resourceType); } - public PerResourcePollingDependentResource(long pollingPeriod) { - this.pollingPeriod = pollingPeriod; + public PerResourcePollingDependentResource(Class resourceType, long pollingPeriod) { + super(resourceType, pollingPeriod); } @Override public EventSource initEventSource(EventSourceContext

context) { eventSource = new PerResourcePollingEventSource<>(this, context.getPrimaryCache(), - pollingPeriod, resourceType()); + getPollingPeriod(), resourceType()); return eventSource; } - - public PerResourcePollingDependentResource setPollingPeriod(long pollingPeriod) { - this.pollingPeriod = pollingPeriod; - return this; - } - - public long getPollingPeriod() { - return pollingPeriod; - } - } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java index 18e0c66b60..58723a6f11 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/external/PollingDependentResource.java @@ -10,27 +10,19 @@ import io.javaoperatorsdk.operator.processing.event.source.polling.PollingEventSource; public abstract class PollingDependentResource - extends AbstractCachingDependentResource implements Supplier> { + extends AbstractPollingDependentResource implements Supplier> { - public static final int DEFAULT_POLLING_PERIOD = 5000; - protected long pollingPeriod; - - public PollingDependentResource() { - this(DEFAULT_POLLING_PERIOD); + public PollingDependentResource(Class resourceType) { + super(resourceType); } - public PollingDependentResource(long pollingPeriod) { - this.pollingPeriod = pollingPeriod; + public PollingDependentResource(Class resourceType, long pollingPeriod) { + super(resourceType, pollingPeriod); } @Override public EventSource initEventSource(EventSourceContext

context) { - eventSource = new PollingEventSource<>(this, pollingPeriod, resourceType()); + eventSource = new PollingEventSource<>(this, getPollingPeriod(), resourceType()); return eventSource; } - - public PollingDependentResource setPollingPeriod(long pollingPeriod) { - this.pollingPeriod = pollingPeriod; - return this; - } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/CrudKubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/CrudKubernetesDependentResource.java index 88e9bdc7ae..b363e81b51 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/CrudKubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/CrudKubernetesDependentResource.java @@ -12,6 +12,10 @@ * @param

Primary Resource */ public abstract class CrudKubernetesDependentResource - extends - KubernetesDependentResource implements Creator, Updater, Deleter

{ + extends KubernetesDependentResource + implements Creator, Updater, Deleter

{ + + public CrudKubernetesDependentResource(Class resourceType) { + super(resourceType); + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 7ceadaf13c..9439d74865 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -11,7 +11,6 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; import io.fabric8.kubernetes.client.dsl.Resource; -import io.javaoperatorsdk.operator.api.config.Utils; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; @@ -21,6 +20,7 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesClientAware; import io.javaoperatorsdk.operator.api.reconciler.dependent.Matcher; import io.javaoperatorsdk.operator.api.reconciler.dependent.Matcher.Result; +import io.javaoperatorsdk.operator.api.reconciler.dependent.ResourceTypeAware; import io.javaoperatorsdk.operator.api.reconciler.dependent.ResourceUpdatePreProcessor; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.EventSource; @@ -31,7 +31,7 @@ public abstract class KubernetesDependentResource extends AbstractDependentResource - implements KubernetesClientAware, EventSourceProvider

, + implements KubernetesClientAware, EventSourceProvider

, ResourceTypeAware, DependentResourceConfigurator { private static final Logger log = LoggerFactory.getLogger(KubernetesDependentResource.class); @@ -41,15 +41,17 @@ public abstract class KubernetesDependentResource matcher; private final ResourceUpdatePreProcessor processor; + private final Class resourceType; @SuppressWarnings("unchecked") - public KubernetesDependentResource() { + public KubernetesDependentResource(Class resourceType) { + this.resourceType = resourceType; matcher = this instanceof Matcher ? (Matcher) this - : GenericKubernetesResourceMatcher.matcherFor(resourceType(), this); + : GenericKubernetesResourceMatcher.matcherFor(resourceType, this); processor = this instanceof ResourceUpdatePreProcessor ? (ResourceUpdatePreProcessor) this - : GenericResourceUpdatePreProcessor.processorFor(resourceType()); + : GenericResourceUpdatePreProcessor.processorFor(resourceType); } @Override @@ -140,9 +142,9 @@ public KubernetesDependentResource setInformerEventSource( return this; } - @SuppressWarnings("unchecked") - protected Class resourceType() { - return (Class) Utils.getFirstTypeArgumentFromExtendedClass(getClass()); + @Override + public Class resourceType() { + return resourceType; } @Override diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/UtilsTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/UtilsTest.java index 8895922e82..0a24d4f26d 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/UtilsTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/UtilsTest.java @@ -1,14 +1,21 @@ package io.javaoperatorsdk.operator.api.config; +import java.util.Optional; + import org.junit.jupiter.api.Test; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.ReconcileResult; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; import io.javaoperatorsdk.operator.sample.simple.TestCustomResource; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; class UtilsTest { @@ -75,12 +82,32 @@ void getsFirstTypeArgumentFromExtendedClass() { assertThat(res).isEqualTo(Deployment.class); } - public static class TestKubernetesDependentResource - extends KubernetesDependentResource { + @Test + void getsFirstTypeArgumentFromInterface() { + assertThat(Utils.getFirstTypeArgumentFromInterface(TestDependentResource.class)) + .isEqualTo(Deployment.class); + } + + public static class TestDependentResource + implements DependentResource { @Override - protected Deployment desired(TestCustomResource primary, Context context) { + public ReconcileResult reconcile(TestCustomResource primary, + Context context) { return null; } + + @Override + public Optional getResource(TestCustomResource primaryResource) { + return Optional.empty(); + } + } + + public static class TestKubernetesDependentResource + extends KubernetesDependentResource { + + public TestKubernetesDependentResource() { + super(Deployment.class); + } } } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcherTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcherTest.java index 1eb7ea1bb4..bad10d551d 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcherTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/GenericKubernetesResourceMatcherTest.java @@ -32,7 +32,7 @@ void checksIfDesiredValuesAreTheSame() { var actual = createDeployment(); final var desired = createDeployment(); final var matcher = GenericKubernetesResourceMatcher.matcherFor(Deployment.class, - new KubernetesDependentResource<>() { + new KubernetesDependentResource<>(Deployment.class) { @Override protected Deployment desired(HasMetadata primary, Context context) { final var currentCase = Optional.ofNullable(primary) diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/readonly/ReadOnlyDependent.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/readonly/ReadOnlyDependent.java index 0285d47b83..15fb02a0b6 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/readonly/ReadOnlyDependent.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/readonly/ReadOnlyDependent.java @@ -4,4 +4,8 @@ import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; public class ReadOnlyDependent extends KubernetesDependentResource { + + public ReadOnlyDependent() { + super(ConfigMap.class); + } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java index 4a236e6e00..e740032d6e 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/standalonedependent/StandaloneDependentTestReconciler.java @@ -7,7 +7,14 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientException; import io.javaoperatorsdk.operator.ReconcilerUtils; -import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler; +import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.javaoperatorsdk.operator.api.reconciler.dependent.Creator; import io.javaoperatorsdk.operator.api.reconciler.dependent.Updater; import io.javaoperatorsdk.operator.junit.KubernetesClientAware; @@ -86,6 +93,10 @@ private static class DeploymentDependentResource extends implements Creator, Updater { + public DeploymentDependentResource() { + super(Deployment.class); + } + @Override protected Deployment desired(StandaloneDependentTestCustomResource primary, Context context) { diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java index f5a5e9ea18..273cd086a1 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SchemaDependentResource.java @@ -16,7 +16,8 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceConfigurator; import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider; import io.javaoperatorsdk.operator.processing.dependent.external.PerResourcePollingDependentResource; -import io.javaoperatorsdk.operator.sample.*; +import io.javaoperatorsdk.operator.sample.MySQLDbConfig; +import io.javaoperatorsdk.operator.sample.MySQLSchema; import io.javaoperatorsdk.operator.sample.schema.Schema; import io.javaoperatorsdk.operator.sample.schema.SchemaService; @@ -35,6 +36,10 @@ public class SchemaDependentResource private MySQLDbConfig dbConfig; + public SchemaDependentResource() { + super(Schema.class); + } + @Override public void configureWith(ResourcePollerConfig config) { this.dbConfig = config.getMySQLDbConfig(); diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java index 15fff4d65e..60c4c4d2b0 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java @@ -22,6 +22,10 @@ public class SecretDependentResource extends KubernetesDependentResource implements Creator, Updater { + public DeploymentDependentResource() { + super(Deployment.class); + } + private static String tomcatImage(Tomcat tomcat) { return "tomcat:" + tomcat.getSpec().getVersion(); } diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java index 3b618906ab..c52553851d 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java @@ -12,6 +12,10 @@ public class ServiceDependentResource extends KubernetesDependentResource implements Creator, Updater { + public ServiceDependentResource() { + super(Service.class); + } + @Override protected Service desired(Tomcat tomcat, Context context) { final ObjectMeta tomcatMetadata = tomcat.getMetadata(); diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconcilerDependentResources.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconcilerDependentResources.java index d9efec3b19..90f747d158 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconcilerDependentResources.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconcilerDependentResources.java @@ -1,15 +1,27 @@ package io.javaoperatorsdk.operator.sample; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.fabric8.kubernetes.api.model.*; +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ConfigMapBuilder; +import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.KubernetesClient; -import io.javaoperatorsdk.operator.api.reconciler.*; import io.javaoperatorsdk.operator.api.reconciler.Context; +import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler; +import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusUpdateControl; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; +import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer; +import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CrudKubernetesDependentResource; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfig; @@ -88,7 +100,7 @@ private void createDependentResources(KubernetesClient client) { .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR)); this.deploymentDR = - new CrudKubernetesDependentResource<>() { + new CrudKubernetesDependentResource<>(Deployment.class) { @Override protected Deployment desired(WebPage webPage, Context context) { @@ -114,18 +126,13 @@ protected Deployment desired(WebPage webPage, Context context) { new ConfigMapVolumeSourceBuilder().withName(configMapName(webPage)).build()); return deployment; } - - @Override - protected Class resourceType() { - return Deployment.class; - } }; deploymentDR.setKubernetesClient(client); deploymentDR.configureWith(new KubernetesDependentResourceConfig() .setLabelSelector(DEPENDENT_RESOURCE_LABEL_SELECTOR)); this.serviceDR = - new CrudKubernetesDependentResource<>() { + new CrudKubernetesDependentResource<>(Service.class) { @Override protected Service desired(WebPage webPage, Context context) { @@ -137,11 +144,6 @@ protected Service desired(WebPage webPage, Context context) { service.getSpec().setSelector(labels); return service; } - - @Override - protected Class resourceType() { - return Service.class; - } }; serviceDR.setKubernetesClient(client); serviceDR.configureWith(new KubernetesDependentResourceConfig() @@ -162,8 +164,11 @@ public static String serviceName(WebPage webPage) { private class ConfigMapDependentResource extends CrudKubernetesDependentResource - implements - PrimaryToSecondaryMapper { + implements PrimaryToSecondaryMapper { + + public ConfigMapDependentResource() { + super(ConfigMap.class); + } @Override protected ConfigMap desired(WebPage webPage, Context context) {