From 7593cc88fc7dc3f82af8ee965e68191384c73112 Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 11 Feb 2022 14:23:37 +0100 Subject: [PATCH 01/10] fix: refactor configuring dependent resources --- .../config/dependent/KubernetesDependent.java | 6 +- ...ernetesDependentResourceConfiguration.java | 35 +++++------ .../informer/InformerConfiguration.java | 24 +------- .../KubernetesDependentResource.java | 58 +++++++++++++------ ...StandaloneKubernetesDependentResource.java | 10 ---- .../operator/processing/Controller.java | 2 +- .../DependentResourceController.java | 12 ++-- .../DependentResourceInitializer.java | 22 +++++++ .../dependent/DependentResourceManager.java | 53 ++++++++--------- ...KubernetesDependentResourceController.java | 30 +++++----- ...ubernetesDependentResourceInitializer.java | 21 +++++++ .../source/informer/InformerEventSource.java | 3 +- .../runtime/AnnotationConfiguration.java | 5 +- 13 files changed, 150 insertions(+), 131 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependent.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependent.java index e7d2ad3158..f442f1c876 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependent.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependent.java @@ -12,15 +12,12 @@ public @interface KubernetesDependent { boolean OWNED_DEFAULT = true; - boolean SKIP_UPDATE_DEFAULT = true; boolean owned() default OWNED_DEFAULT; - boolean skipUpdateIfUnchanged() default SKIP_UPDATE_DEFAULT; - /** * Specified which namespaces this Controller monitors for custom resources events. If no - * namespace is specified then the controller will monitor all namespaces by default. + * namespace is specified then the controller will monitor the namespaces configured for the controller. * * @return the list of namespaces this controller monitors */ @@ -34,4 +31,5 @@ * @return the label selector */ String labelSelector() default EMPTY_STRING; + } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java index 6872322e4f..3e61d6eaf8 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java @@ -4,34 +4,33 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.config.ConfigurationService; +import io.javaoperatorsdk.operator.api.config.DefaultResourceConfiguration; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; -import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; -import io.javaoperatorsdk.operator.processing.event.source.PrimaryResourcesRetriever; public interface KubernetesDependentResourceConfiguration - extends InformerConfiguration, DependentResourceConfiguration { + extends DependentResourceConfiguration { class DefaultKubernetesDependentResourceConfiguration - extends DefaultInformerConfiguration + extends DefaultResourceConfiguration implements KubernetesDependentResourceConfiguration { - private final boolean owned; + private final Class> dependentResourceClass; + private final boolean owned; protected DefaultKubernetesDependentResourceConfiguration( - ConfigurationService service, + ConfigurationService configurationService, String labelSelector, Class resourceClass, - PrimaryResourcesRetriever secondaryToPrimaryResourcesIdSet, - AssociatedSecondaryResourceIdentifier

associatedWith, - boolean skipUpdateEventPropagationIfNoChange, Set namespaces, boolean owned, + Set namespaces, boolean owned, Class> dependentResourceClass) { - super(service, labelSelector, resourceClass, secondaryToPrimaryResourcesIdSet, associatedWith, - skipUpdateEventPropagationIfNoChange, namespaces); + super(labelSelector, resourceClass, namespaces); + setConfigurationService(configurationService); this.owned = owned; this.dependentResourceClass = dependentResourceClass; } + @Override public boolean isOwned() { return owned; } @@ -40,27 +39,19 @@ public boolean isOwned() { public Class> getDependentResourceClass() { return dependentResourceClass; } - - @Override - public Class getResourceClass() { - return super.getResourceClass(); - } } static KubernetesDependentResourceConfiguration from( InformerConfiguration cfg, boolean owned, Class dependentResourceClass) { return new DefaultKubernetesDependentResourceConfiguration(cfg.getConfigurationService(), - cfg.getLabelSelector(), cfg.getResourceClass(), cfg.getPrimaryResourcesRetriever(), - cfg.getAssociatedResourceIdentifier(), cfg.isSkipUpdateEventPropagationIfNoChange(), + cfg.getLabelSelector(), cfg.getResourceClass(), cfg.getNamespaces(), owned, (Class>) dependentResourceClass); } + Class> getDependentResourceClass(); + boolean isOwned(); - @Override - default Class getResourceClass() { - return InformerConfiguration.super.getResourceClass(); - } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java index c4d747a990..acb5bd23c4 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/informer/InformerConfiguration.java @@ -22,13 +22,12 @@ class DefaultInformerConfiguration private final PrimaryResourcesRetriever secondaryToPrimaryResourcesIdSet; private final AssociatedSecondaryResourceIdentifier

associatedWith; - private final boolean skipUpdateEventPropagationIfNoChange; protected DefaultInformerConfiguration(ConfigurationService service, String labelSelector, Class resourceClass, PrimaryResourcesRetriever secondaryToPrimaryResourcesIdSet, AssociatedSecondaryResourceIdentifier

associatedWith, - boolean skipUpdateEventPropagationIfNoChange, Set namespaces) { + Set namespaces) { super(labelSelector, resourceClass, namespaces); setConfigurationService(service); this.secondaryToPrimaryResourcesIdSet = @@ -36,7 +35,6 @@ protected DefaultInformerConfiguration(ConfigurationService service, String labe Mappers.fromOwnerReference()); this.associatedWith = Objects.requireNonNullElseGet(associatedWith, () -> ResourceID::fromResource); - this.skipUpdateEventPropagationIfNoChange = skipUpdateEventPropagationIfNoChange; } public PrimaryResourcesRetriever getPrimaryResourcesRetriever() { @@ -47,22 +45,16 @@ public AssociatedSecondaryResourceIdentifier

getAssociatedResourceIdentifier( return associatedWith; } - public boolean isSkipUpdateEventPropagationIfNoChange() { - return skipUpdateEventPropagationIfNoChange; - } } PrimaryResourcesRetriever getPrimaryResourcesRetriever(); AssociatedSecondaryResourceIdentifier

getAssociatedResourceIdentifier(); - boolean isSkipUpdateEventPropagationIfNoChange(); - class InformerConfigurationBuilder { private PrimaryResourcesRetriever secondaryToPrimaryResourcesIdSet; private AssociatedSecondaryResourceIdentifier

associatedWith; - private boolean skipUpdateEventPropagationIfNoChange = true; private Set namespaces; private String labelSelector; private final Class resourceClass; @@ -86,16 +78,6 @@ public InformerConfigurationBuilder withAssociatedSecondaryResourceIdentif return this; } - public InformerConfigurationBuilder withoutSkippingEventPropagationIfUnchanged() { - this.skipUpdateEventPropagationIfNoChange = false; - return this; - } - - public InformerConfigurationBuilder skippingEventPropagationIfUnchanged( - boolean skipIfUnchanged) { - this.skipUpdateEventPropagationIfNoChange = skipIfUnchanged; - return this; - } public InformerConfigurationBuilder withNamespaces(String... namespaces) { this.namespaces = namespaces != null ? Set.of(namespaces) : Collections.emptySet(); @@ -115,7 +97,7 @@ public InformerConfigurationBuilder withLabelSelector(String labelSelector public InformerConfiguration build() { return new DefaultInformerConfiguration<>(configurationService, labelSelector, resourceClass, - secondaryToPrimaryResourcesIdSet, associatedWith, skipUpdateEventPropagationIfNoChange, + secondaryToPrimaryResourcesIdSet, associatedWith, namespaces); } } @@ -136,8 +118,6 @@ static InformerConfigurationBuild configuration.getConfigurationService()) .withNamespaces(configuration.getNamespaces()) .withLabelSelector(configuration.getLabelSelector()) - .skippingEventPropagationIfUnchanged( - configuration.isSkipUpdateEventPropagationIfNoChange()) .withAssociatedSecondaryResourceIdentifier( configuration.getAssociatedResourceIdentifier()) .withPrimaryResourcesRetriever(configuration.getPrimaryResourcesRetriever()); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java index e8a4a6779e..1c90e5d504 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -2,6 +2,7 @@ import java.util.Optional; +import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependentResourceConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,6 +28,11 @@ public abstract class KubernetesDependentResource informerEventSource; + private DesiredSupplier desiredSupplier = null; + private Class resourceType = null; + private AssociatedSecondaryResourceIdentifier

associatedSecondaryResourceIdentifier = + ResourceID::fromResource; + private PrimaryResourcesRetriever primaryResourcesRetriever = Mappers.fromOwnerReference(); public KubernetesDependentResource() { this(null); @@ -36,6 +42,15 @@ public KubernetesDependentResource(KubernetesClient client) { this.client = client; } + // todo builder + public void initWithConfiguration(KubernetesDependentResourceConfiguration config) { + this.owned = config.isOwned(); + + InformerConfiguration.DefaultInformerConfiguration ic = new InformerConfiguration.DefaultInformerConfiguration() + InformerConfiguration.from(ic); +// InformerEventSource ies = new InformerEventSource() + } + protected void beforeCreateOrUpdate(R desired, P primary) { if (owned) { desired.addOwnerReference(primary); @@ -75,34 +90,29 @@ public Optional eventSource(EventSourceContext

context) { if (informerEventSource != null) { return Optional.of(informerEventSource); } - var informerConfig = initInformerConfiguration(context); + var informerConfig = initDefaultInformerConfiguration(context); informerEventSource = new InformerEventSource(informerConfig, context); return Optional.of(informerEventSource); } @SuppressWarnings("unchecked") - private InformerConfiguration initInformerConfiguration(EventSourceContext

context) { - PrimaryResourcesRetriever associatedPrimaries = - (this instanceof PrimaryResourcesRetriever) ? (PrimaryResourcesRetriever) this - : getDefaultPrimaryResourcesRetriever(); - - AssociatedSecondaryResourceIdentifier

associatedSecondary = - (this instanceof AssociatedSecondaryResourceIdentifier) - ? (AssociatedSecondaryResourceIdentifier

) this - : getDefaultAssociatedSecondaryResourceIdentifier(); - + private InformerConfiguration initDefaultInformerConfiguration(EventSourceContext

context) { return InformerConfiguration.from(context, resourceType()) - .withPrimaryResourcesRetriever(associatedPrimaries) - .withAssociatedSecondaryResourceIdentifier(associatedSecondary) + .withPrimaryResourcesRetriever(getPrimaryResourcesRetriever()) + .withAssociatedSecondaryResourceIdentifier(getAssociatedSecondaryResourceIdentifier()) .build(); } - protected AssociatedSecondaryResourceIdentifier

getDefaultAssociatedSecondaryResourceIdentifier() { - return ResourceID::fromResource; + + protected PrimaryResourcesRetriever getPrimaryResourcesRetriever() { + return (this instanceof PrimaryResourcesRetriever) ? (PrimaryResourcesRetriever) this + : primaryResourcesRetriever; } - protected PrimaryResourcesRetriever getDefaultPrimaryResourcesRetriever() { - return Mappers.fromOwnerReference(); + protected AssociatedSecondaryResourceIdentifier

getAssociatedSecondaryResourceIdentifier() { + return (this instanceof AssociatedSecondaryResourceIdentifier) + ? (AssociatedSecondaryResourceIdentifier

) this + : associatedSecondaryResourceIdentifier; } public KubernetesDependentResource setInformerEventSource( @@ -147,4 +157,18 @@ public KubernetesDependentResource setOwned(boolean owned) { this.owned = owned; return this; } + + @Override + public Class resourceType() { + if (resourceType != null) { + return resourceType; + } else { + return super.resourceType(); + } + } + + @Override + protected R desired(P primary, Context context) { + return desiredSupplier.getDesired(primary, context); + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java index d4d1e00dc2..2be121a519 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java @@ -50,14 +50,4 @@ public StandaloneKubernetesDependentResource setPrimaryResourcesRetriever( this.primaryResourcesRetriever = primaryResourcesRetriever; return this; } - - @Override - protected AssociatedSecondaryResourceIdentifier

getDefaultAssociatedSecondaryResourceIdentifier() { - return this.associatedSecondaryResourceIdentifier; - } - - @Override - protected PrimaryResourcesRetriever getDefaultPrimaryResourcesRetriever() { - return this.primaryResourcesRetriever; - } } 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 f3ad2dd8ec..00a24ee1a0 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 @@ -56,7 +56,7 @@ public Controller(Reconciler reconciler, this.kubernetesClient = kubernetesClient; eventSourceManager = new EventSourceManager<>(this); - dependents = new DependentResourceManager<>(this); + dependents = new DependentResourceManager<>(this,kubernetesClient); } @Override diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java index e49a55a73a..078330e40d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java @@ -10,21 +10,21 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; import io.javaoperatorsdk.operator.processing.event.source.EventSource; +// todo delete controllers @Ignore public class DependentResourceController, D extends DependentResource> implements DependentResource { - private final D delegate; - private final C configuration; + protected final D delegate; + protected final C configuration; public DependentResourceController(D delegate, C configuration) { this.delegate = delegate; - this.configuration = initConfiguration(delegate, configuration); + this.configuration = configuration; + applyConfigurationToDelegate(delegate,configuration); } - protected C initConfiguration(D delegate, C configuration) { - // default implementation just returns the specified one - return configuration; + protected void applyConfigurationToDelegate(D delegate, C configuration) { } @Override diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java new file mode 100644 index 0000000000..e26f53fb17 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java @@ -0,0 +1,22 @@ +package io.javaoperatorsdk.operator.processing.dependent; + +import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; + +import java.lang.reflect.InvocationTargetException; + +public class DependentResourceInitializer< + T extends DependentResource, K extends DependentResourceConfiguration> { + + public T initDependentResource(K config, KubernetesClient kubernetesClient) { + try { + return (T) config.getDependentResourceClass().getConstructor().newInstance(); + } catch (InstantiationException + | IllegalAccessException + | InvocationTargetException + | NoSuchMethodException e) { + throw new IllegalStateException(e); + } + } +} 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 index ac791526fc..95ac268014 100644 --- 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 @@ -28,29 +28,33 @@ public class DependentResourceManager

implements EventSourceInitializer

, EventSourceContextInjector, Reconciler

{ private final Reconciler

reconciler; - private final ControllerConfiguration

configuration; - private List dependents; + private final ControllerConfiguration

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

controller) { + public DependentResourceManager(Controller

controller, KubernetesClient kubernetesClient) { this.reconciler = controller.getReconciler(); - this.configuration = controller.getConfiguration(); + this.controllerConfiguration = controller.getConfiguration(); + initDependentResourceControllers(kubernetesClient); + } + + private void initDependentResourceControllers(KubernetesClient kubernetesClient) { + final List dependentResourceConfigurations + = controllerConfiguration.getDependentResources(); + dependents = new ArrayList<>(dependentResourceConfigurations.size()); + dependentResourceConfigurations.forEach(dependent -> { + final var dependentResourceController = from(dependent, kubernetesClient); + dependents.add(dependentResourceController); + }); } @Override public List prepareEventSources(EventSourceContext

context) { - final List configured = configuration.getDependentResources(); - dependents = new ArrayList<>(configured.size()); - - List sources = new ArrayList<>(configured.size() + 5); - configured.forEach(dependent -> { - final var dependentResourceController = from(dependent, context.getClient()); - dependents.add(dependentResourceController); - dependentResourceController.eventSource(context) + List sources = new ArrayList<>(); + dependents.forEach(dependent -> { + dependent.eventSource(context) .ifPresent(es -> sources.add((EventSource) es)); - }); - return sources; } @@ -84,29 +88,20 @@ private void initContextIfNeeded(P resource, Context context) { } } - private DependentResourceController from(DependentResourceConfiguration config, + private DependentResource from(DependentResourceConfiguration config, KubernetesClient client) { - try { - final var dependentResource = - (DependentResource) config.getDependentResourceClass().getConstructor() - .newInstance(); if (config instanceof KubernetesDependentResourceConfiguration) { - if (dependentResource instanceof KubernetesDependentResource) { - final var kubeDependentResource = (KubernetesDependentResource) dependentResource; - kubeDependentResource.setClient(client); - return new KubernetesDependentResourceController(kubeDependentResource, - (KubernetesDependentResourceConfiguration) config); + if (config.getDependentResourceClass().isAssignableFrom(KubernetesDependentResource.class)) { + KubernetesDependentResourceInitializer dependentResourceInitializer = new KubernetesDependentResourceInitializer(); + return dependentResourceInitializer.initDependentResource((KubernetesDependentResourceConfiguration) config,client); } else { throw new IllegalArgumentException("A " + KubernetesDependentResourceConfiguration.class.getCanonicalName() + " must be associated to a " + KubernetesDependentResource.class.getCanonicalName()); } } else { - return new DependentResourceController(dependentResource, config); + DependentResourceInitializer dependentResourceInitializer = new DependentResourceInitializer(); + return dependentResourceInitializer.initDependentResource(config,client); } - } catch (NoSuchMethodException | InvocationTargetException | InstantiationException - | IllegalAccessException e) { - throw new IllegalArgumentException(e); - } } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java index 733460ef31..f3beb85c54 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java @@ -25,32 +25,34 @@ public KubernetesDependentResourceController(KubernetesDependentResource d @SuppressWarnings("unchecked") @Override - protected KubernetesDependentResourceConfiguration initConfiguration( + protected void applyConfigurationToDelegate( KubernetesDependentResource delegate, KubernetesDependentResourceConfiguration configuration) { - // todo: check if we can validate that types actually match properly + delegate.setOwned(configuration.isOwned()); + final var associatedPrimaries = (delegate instanceof PrimaryResourcesRetriever) - ? (PrimaryResourcesRetriever) delegate - : configuration.getPrimaryResourcesRetriever(); + ? (PrimaryResourcesRetriever) delegate : null; + final var associatedSecondary = (delegate instanceof AssociatedSecondaryResourceIdentifier) ? (AssociatedSecondaryResourceIdentifier

) delegate - : configuration.getAssociatedResourceIdentifier(); - - final var augmented = InformerConfiguration.from(configuration) - .withPrimaryResourcesRetriever(associatedPrimaries) - .withAssociatedSecondaryResourceIdentifier(associatedSecondary) - .build(); - return KubernetesDependentResourceConfiguration.from(augmented, configuration.isOwned(), - configuration.getDependentResourceClass()); + : null; + +// final var augmented = InformerConfiguration.from(configuration) +// .withPrimaryResourcesRetriever(associatedPrimaries) +// .withAssociatedSecondaryResourceIdentifier(associatedSecondary) +// .build(); +// return KubernetesDependentResourceConfiguration.from(augmented, configuration.isOwned(), +// configuration.getDependentResourceClass()); + } @Override public Optional eventSource(EventSourceContext

context) { - var informer = new InformerEventSource<>(getConfiguration(), context); +// var informer = new InformerEventSource<>(getConfiguration(), context); // todo have this implemented with nicer abstractions - delegate().setInformerEventSource(informer); +// delegate().setInformerEventSource(informer); return super.eventSource(context); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java new file mode 100644 index 0000000000..7081917970 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java @@ -0,0 +1,21 @@ +package io.javaoperatorsdk.operator.processing.dependent; + +import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependentResourceConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; + +public class KubernetesDependentResourceInitializer extends + DependentResourceInitializer, KubernetesDependentResourceConfiguration> { + + @Override + public KubernetesDependentResource initDependentResource(KubernetesDependentResourceConfiguration config, + KubernetesClient client) { + + // todo with constructor, require a specific constructor args ?! + KubernetesDependentResource kubernetesDependentResource = super.initDependentResource(config,client); + kubernetesDependentResource.setClient(client); + kubernetesDependentResource.initWithConfiguration(config); + return kubernetesDependentResource; + } + +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index 3def733bd8..2e025f30a7 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -50,8 +50,7 @@ public void onUpdate(T oldObject, T newObject) { return; } - if (configuration.isSkipUpdateEventPropagationIfNoChange() && - oldObject.getMetadata().getResourceVersion() + if (oldObject.getMetadata().getResourceVersion() .equals(newObject.getMetadata().getResourceVersion())) { return; } diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationConfiguration.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationConfiguration.java index 19e31e932b..ab38d537d7 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationConfiguration.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationConfiguration.java @@ -165,12 +165,9 @@ public List getDependentResources() { valueOrDefault(kubeDependent, KubernetesDependent::labelSelector, null); final var owned = valueOrDefault(kubeDependent, KubernetesDependent::owned, KubernetesDependent.OWNED_DEFAULT); - final var skipIfUnchanged = - valueOrDefault(kubeDependent, KubernetesDependent::skipUpdateIfUnchanged, - KubernetesDependent.SKIP_UPDATE_DEFAULT); + final var configuration = InformerConfiguration.from(service, resourceType) .withLabelSelector(labelSelector) - .skippingEventPropagationIfUnchanged(skipIfUnchanged) .withNamespaces(namespaces) .build(); From d8eb980c75c47667ccbe8f50f5504c2ed8aa246c Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 11 Feb 2022 14:43:50 +0100 Subject: [PATCH 02/10] fix: refactor --- .../config/dependent/KubernetesDependent.java | 3 +- ...ernetesDependentResourceConfiguration.java | 14 +++- .../reconciler/ControllerConfiguration.java | 6 -- .../KubernetesDependentResource.java | 53 +++++++++++---- ...StandaloneKubernetesDependentResource.java | 53 --------------- .../operator/processing/Controller.java | 2 +- .../DependentResourceController.java | 66 ------------------- .../DependentResourceInitializer.java | 9 ++- .../dependent/DependentResourceManager.java | 30 +++++---- ...KubernetesDependentResourceController.java | 58 ---------------- ...ubernetesDependentResourceInitializer.java | 22 ++++--- .../event/source/EventSourceContextAware.java | 8 --- .../source/informer/InformerEventSource.java | 19 ++---- .../informer/ManagedInformerEventSource.java | 1 - .../StandaloneDependentTestReconciler.java | 6 +- .../operator/sample/WebPageReconciler.java | 14 ++-- 16 files changed, 106 insertions(+), 258 deletions(-) delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSourceContextAware.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependent.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependent.java index f442f1c876..64fc656f65 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependent.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependent.java @@ -17,7 +17,8 @@ /** * Specified which namespaces this Controller monitors for custom resources events. If no - * namespace is specified then the controller will monitor the namespaces configured for the controller. + * namespace is specified then the controller will monitor the namespaces configured for the + * controller. * * @return the list of namespaces this controller monitors */ diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java index 3e61d6eaf8..6c0f8b3067 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java @@ -5,11 +5,18 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.config.ConfigurationService; import io.javaoperatorsdk.operator.api.config.DefaultResourceConfiguration; +import io.javaoperatorsdk.operator.api.config.ResourceConfiguration; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; public interface KubernetesDependentResourceConfiguration - extends DependentResourceConfiguration { + extends DependentResourceConfiguration, ResourceConfiguration { + + @Override + ConfigurationService getConfigurationService(); + + @Override + void setConfigurationService(ConfigurationService service); class DefaultKubernetesDependentResourceConfiguration extends DefaultResourceConfiguration @@ -52,6 +59,11 @@ static KubernetesDependentResourc Class> getDependentResourceClass(); + @Override + default Class getResourceClass() { + return null; + } + boolean isOwned(); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java index 85eed38025..0c9276211e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java @@ -7,7 +7,6 @@ import java.util.concurrent.TimeUnit; import io.javaoperatorsdk.operator.api.config.dependent.Dependent; -import io.javaoperatorsdk.operator.processing.dependent.DependentResourceController; import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter; @Retention(RetentionPolicy.RUNTIME) @@ -65,11 +64,6 @@ ReconciliationMaxInterval reconciliationMaxInterval() default @ReconciliationMax /** - * Optional list of classes providing {@link DependentResourceController} implementations - * encapsulating logic to handle the associated - * {@link io.javaoperatorsdk.operator.processing.Controller}'s reconciliation of dependent - * resources - * * @return the list of {@link DependentResourceController} implementations */ Dependent[] dependents() default {}; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java index 1c90e5d504..254bd8ee7e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -2,13 +2,13 @@ import java.util.Optional; -import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependentResourceConfiguration; 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.ReconcilerUtils; +import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependentResourceConfiguration; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; @@ -31,7 +31,7 @@ public abstract class KubernetesDependentResource desiredSupplier = null; private Class resourceType = null; private AssociatedSecondaryResourceIdentifier

associatedSecondaryResourceIdentifier = - ResourceID::fromResource; + ResourceID::fromResource; private PrimaryResourcesRetriever primaryResourcesRetriever = Mappers.fromOwnerReference(); public KubernetesDependentResource() { @@ -42,13 +42,29 @@ public KubernetesDependentResource(KubernetesClient client) { this.client = client; } - // todo builder - public void initWithConfiguration(KubernetesDependentResourceConfiguration config) { - this.owned = config.isOwned(); + public KubernetesDependentResource( + KubernetesClient client, Class resourceType, DesiredSupplier desiredSupplier) { + this.client = client; + this.resourceType = resourceType; + this.desiredSupplier = desiredSupplier; + } + + public KubernetesDependentResource( + Class resourceType, DesiredSupplier desiredSupplier) { + this(null, resourceType, desiredSupplier); + } - InformerConfiguration.DefaultInformerConfiguration ic = new InformerConfiguration.DefaultInformerConfiguration() - InformerConfiguration.from(ic); -// InformerEventSource ies = new InformerEventSource() + // todo builder and/or factory methods + public void initWithConfiguration(KubernetesDependentResourceConfiguration config) { + this.owned = config.isOwned(); + InformerConfiguration ic = + InformerConfiguration.from(config.getConfigurationService(), resourceType()) + .withLabelSelector(config.getLabelSelector()) + .withNamespaces(config.getNamespaces()) + .withPrimaryResourcesRetriever(getPrimaryResourcesRetriever()) + .withAssociatedSecondaryResourceIdentifier(getAssociatedSecondaryResourceIdentifier()) + .build(); + informerEventSource = new InformerEventSource<>(ic, client); } protected void beforeCreateOrUpdate(R desired, P primary) { @@ -96,7 +112,8 @@ public Optional eventSource(EventSourceContext

context) { } @SuppressWarnings("unchecked") - private InformerConfiguration initDefaultInformerConfiguration(EventSourceContext

context) { + private InformerConfiguration initDefaultInformerConfiguration( + EventSourceContext

context) { return InformerConfiguration.from(context, resourceType()) .withPrimaryResourcesRetriever(getPrimaryResourcesRetriever()) .withAssociatedSecondaryResourceIdentifier(getAssociatedSecondaryResourceIdentifier()) @@ -106,13 +123,13 @@ private InformerConfiguration initDefaultInformerConfiguration(EventSource protected PrimaryResourcesRetriever getPrimaryResourcesRetriever() { return (this instanceof PrimaryResourcesRetriever) ? (PrimaryResourcesRetriever) this - : primaryResourcesRetriever; + : primaryResourcesRetriever; } protected AssociatedSecondaryResourceIdentifier

getAssociatedSecondaryResourceIdentifier() { return (this instanceof AssociatedSecondaryResourceIdentifier) - ? (AssociatedSecondaryResourceIdentifier

) this - : associatedSecondaryResourceIdentifier; + ? (AssociatedSecondaryResourceIdentifier

) this + : associatedSecondaryResourceIdentifier; } public KubernetesDependentResource setInformerEventSource( @@ -171,4 +188,16 @@ public Class resourceType() { protected R desired(P primary, Context context) { return desiredSupplier.getDesired(primary, context); } + + public KubernetesDependentResource setAssociatedSecondaryResourceIdentifier( + AssociatedSecondaryResourceIdentifier

associatedSecondaryResourceIdentifier) { + this.associatedSecondaryResourceIdentifier = associatedSecondaryResourceIdentifier; + return this; + } + + public KubernetesDependentResource setPrimaryResourcesRetriever( + PrimaryResourcesRetriever primaryResourcesRetriever) { + this.primaryResourcesRetriever = primaryResourcesRetriever; + return this; + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java deleted file mode 100644 index 2be121a519..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/StandaloneKubernetesDependentResource.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.javaoperatorsdk.operator.api.reconciler.dependent; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.fabric8.kubernetes.client.KubernetesClient; -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; -import io.javaoperatorsdk.operator.processing.event.source.PrimaryResourcesRetriever; -import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; - -// todo shorter name -public class StandaloneKubernetesDependentResource - extends KubernetesDependentResource { - - private final DesiredSupplier desiredSupplier; - private final Class resourceType; - private AssociatedSecondaryResourceIdentifier

associatedSecondaryResourceIdentifier = - ResourceID::fromResource; - private PrimaryResourcesRetriever primaryResourcesRetriever = Mappers.fromOwnerReference(); - - public StandaloneKubernetesDependentResource( - Class resourceType, DesiredSupplier desiredSupplier) { - this(null, resourceType, desiredSupplier); - } - - public StandaloneKubernetesDependentResource( - KubernetesClient client, Class resourceType, DesiredSupplier desiredSupplier) { - super(client); - this.desiredSupplier = desiredSupplier; - this.resourceType = resourceType; - } - - @Override - protected R desired(P primary, Context context) { - return desiredSupplier.getDesired(primary, context); - } - - public Class resourceType() { - return resourceType; - } - - public StandaloneKubernetesDependentResource setAssociatedSecondaryResourceIdentifier( - AssociatedSecondaryResourceIdentifier

associatedSecondaryResourceIdentifier) { - this.associatedSecondaryResourceIdentifier = associatedSecondaryResourceIdentifier; - return this; - } - - public StandaloneKubernetesDependentResource setPrimaryResourcesRetriever( - PrimaryResourcesRetriever primaryResourcesRetriever) { - this.primaryResourcesRetriever = primaryResourcesRetriever; - return this; - } -} 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 00a24ee1a0..d0c86475d3 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 @@ -56,7 +56,7 @@ public Controller(Reconciler reconciler, this.kubernetesClient = kubernetesClient; eventSourceManager = new EventSourceManager<>(this); - dependents = new DependentResourceManager<>(this,kubernetesClient); + dependents = new DependentResourceManager<>(this, kubernetesClient); } @Override diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java deleted file mode 100644 index 078330e40d..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceController.java +++ /dev/null @@ -1,66 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent; - -import java.util.Optional; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.Ignore; -import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; -import io.javaoperatorsdk.operator.processing.event.source.EventSource; - -// todo delete controllers -@Ignore -public class DependentResourceController, D extends DependentResource> - implements DependentResource { - - protected final D delegate; - protected final C configuration; - - public DependentResourceController(D delegate, C configuration) { - this.delegate = delegate; - this.configuration = configuration; - applyConfigurationToDelegate(delegate,configuration); - } - - protected void applyConfigurationToDelegate(D delegate, C configuration) { - } - - @Override - public Class resourceType() { - return delegate.resourceType(); - } - - @Override - public void delete(P primary, Context context) { - delegate.delete(primary, context); - } - - @Override - public Optional getResource(P primaryResource) { - return delegate.getResource(primaryResource); - } - - - @Override - public Optional eventSource(EventSourceContext

context) { - return delegate.eventSource(context); - } - - - public C getConfiguration() { - return configuration; - } - - protected D delegate() { - return delegate; - } - - @Override - public void reconcile(P resource, Context context) { - delegate.reconcile(resource, context); - } - - -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java index e26f53fb17..a00e5b47bf 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java @@ -1,15 +1,14 @@ package io.javaoperatorsdk.operator.processing.dependent; +import java.lang.reflect.InvocationTargetException; + import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; -import java.lang.reflect.InvocationTargetException; - -public class DependentResourceInitializer< - T extends DependentResource, K extends DependentResourceConfiguration> { +public class DependentResourceInitializer, K extends DependentResourceConfiguration> { - public T initDependentResource(K config, KubernetesClient kubernetesClient) { + public T initDependentResource(K config, KubernetesClient kubernetesClient) { try { return (T) config.getDependentResourceClass().getConstructor().newInstance(); } catch (InstantiationException 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 index 95ac268014..88afc1fbd3 100644 --- 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 @@ -1,6 +1,5 @@ package io.javaoperatorsdk.operator.processing.dependent; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; @@ -39,8 +38,8 @@ public DependentResourceManager(Controller

controller, KubernetesClient kuber } private void initDependentResourceControllers(KubernetesClient kubernetesClient) { - final List dependentResourceConfigurations - = controllerConfiguration.getDependentResources(); + final List dependentResourceConfigurations = + controllerConfiguration.getDependentResources(); dependents = new ArrayList<>(dependentResourceConfigurations.size()); dependentResourceConfigurations.forEach(dependent -> { final var dependentResourceController = from(dependent, kubernetesClient); @@ -90,18 +89,21 @@ private void initContextIfNeeded(P resource, Context context) { private DependentResource from(DependentResourceConfiguration config, KubernetesClient client) { - if (config instanceof KubernetesDependentResourceConfiguration) { - if (config.getDependentResourceClass().isAssignableFrom(KubernetesDependentResource.class)) { - KubernetesDependentResourceInitializer dependentResourceInitializer = new KubernetesDependentResourceInitializer(); - return dependentResourceInitializer.initDependentResource((KubernetesDependentResourceConfiguration) config,client); - } else { - throw new IllegalArgumentException("A " - + KubernetesDependentResourceConfiguration.class.getCanonicalName() - + " must be associated to a " + KubernetesDependentResource.class.getCanonicalName()); - } + if (config instanceof KubernetesDependentResourceConfiguration) { + if (config.getDependentResourceClass().isAssignableFrom(KubernetesDependentResource.class)) { + KubernetesDependentResourceInitializer dependentResourceInitializer = + new KubernetesDependentResourceInitializer(); + return dependentResourceInitializer + .initDependentResource((KubernetesDependentResourceConfiguration) config, client); } else { - DependentResourceInitializer dependentResourceInitializer = new DependentResourceInitializer(); - return dependentResourceInitializer.initDependentResource(config,client); + throw new IllegalArgumentException("A " + + KubernetesDependentResourceConfiguration.class.getCanonicalName() + + " must be associated to a " + KubernetesDependentResource.class.getCanonicalName()); } + } else { + DependentResourceInitializer dependentResourceInitializer = + new DependentResourceInitializer(); + return dependentResourceInitializer.initDependentResource(config, client); + } } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java deleted file mode 100644 index f3beb85c54..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceController.java +++ /dev/null @@ -1,58 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent; - -import java.util.Optional; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependentResourceConfiguration; -import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.Ignore; -import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; -import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; -import io.javaoperatorsdk.operator.processing.event.source.EventSource; -import io.javaoperatorsdk.operator.processing.event.source.PrimaryResourcesRetriever; -import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; - -@Ignore -public class KubernetesDependentResourceController - extends - DependentResourceController, KubernetesDependentResource> { - - public KubernetesDependentResourceController(KubernetesDependentResource delegate, - KubernetesDependentResourceConfiguration configuration) { - super(delegate, configuration); - } - - @SuppressWarnings("unchecked") - @Override - protected void applyConfigurationToDelegate( - KubernetesDependentResource delegate, - KubernetesDependentResourceConfiguration configuration) { - delegate.setOwned(configuration.isOwned()); - - final var associatedPrimaries = - (delegate instanceof PrimaryResourcesRetriever) - ? (PrimaryResourcesRetriever) delegate : null; - - final var associatedSecondary = - (delegate instanceof AssociatedSecondaryResourceIdentifier) - ? (AssociatedSecondaryResourceIdentifier

) delegate - : null; - -// final var augmented = InformerConfiguration.from(configuration) -// .withPrimaryResourcesRetriever(associatedPrimaries) -// .withAssociatedSecondaryResourceIdentifier(associatedSecondary) -// .build(); -// return KubernetesDependentResourceConfiguration.from(augmented, configuration.isOwned(), -// configuration.getDependentResourceClass()); - - } - - @Override - public Optional eventSource(EventSourceContext

context) { -// var informer = new InformerEventSource<>(getConfiguration(), context); - // todo have this implemented with nicer abstractions -// delegate().setInformerEventSource(informer); - return super.eventSource(context); - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java index 7081917970..eb544c76e9 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java @@ -5,17 +5,19 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; public class KubernetesDependentResourceInitializer extends - DependentResourceInitializer, KubernetesDependentResourceConfiguration> { + DependentResourceInitializer, KubernetesDependentResourceConfiguration> { - @Override - public KubernetesDependentResource initDependentResource(KubernetesDependentResourceConfiguration config, - KubernetesClient client) { + @Override + public KubernetesDependentResource initDependentResource( + KubernetesDependentResourceConfiguration config, + KubernetesClient client) { - // todo with constructor, require a specific constructor args ?! - KubernetesDependentResource kubernetesDependentResource = super.initDependentResource(config,client); - kubernetesDependentResource.setClient(client); - kubernetesDependentResource.initWithConfiguration(config); - return kubernetesDependentResource; - } + // todo with constructor, require a specific constructor args ?! + KubernetesDependentResource kubernetesDependentResource = + super.initDependentResource(config, client); + kubernetesDependentResource.setClient(client); + kubernetesDependentResource.initWithConfiguration(config); + return kubernetesDependentResource; + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSourceContextAware.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSourceContextAware.java deleted file mode 100644 index 95042d0c41..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/EventSourceContextAware.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.javaoperatorsdk.operator.processing.event.source; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; - -public interface EventSourceContextAware

{ - void initWith(EventSourceContext

context); -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java index 2e025f30a7..b29209f9e5 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSource.java @@ -5,12 +5,12 @@ import java.util.stream.Stream; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.informers.ResourceEventHandler; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.processing.event.Event; import io.javaoperatorsdk.operator.processing.event.EventHandler; -import io.javaoperatorsdk.operator.processing.event.source.EventSourceContextAware; import io.javaoperatorsdk.operator.processing.event.source.ResourceCache; public class InformerEventSource @@ -23,17 +23,12 @@ public InformerEventSource(InformerConfiguration configuration, EventSourceContext

context) { super(context.getClient().resources(configuration.getResourceClass()), configuration); this.configuration = configuration; + } - // init mappers with context if needed - final var primaryResourcesRetriever = configuration.getPrimaryResourcesRetriever(); - if (primaryResourcesRetriever instanceof EventSourceContextAware) { - ((EventSourceContextAware) primaryResourcesRetriever).initWith(context); - } - - final var associatedResourceIdentifier = configuration.getAssociatedResourceIdentifier(); - if (associatedResourceIdentifier instanceof EventSourceContextAware) { - ((EventSourceContextAware) associatedResourceIdentifier).initWith(context); - } + public InformerEventSource(InformerConfiguration configuration, + KubernetesClient client) { + super(client.resources(configuration.getResourceClass()), configuration); + this.configuration = configuration; } @Override @@ -51,7 +46,7 @@ public void onUpdate(T oldObject, T newObject) { } if (oldObject.getMetadata().getResourceVersion() - .equals(newObject.getMetadata().getResourceVersion())) { + .equals(newObject.getMetadata().getResourceVersion())) { return; } propagateEvent(newObject); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java index f0a1a1185d..1dcfa2aa0e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/ManagedInformerEventSource.java @@ -34,7 +34,6 @@ public void start() { super.start(); } - @Override public void stop() { super.stop(); 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 695cc30a31..337b619af2 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 @@ -9,7 +9,7 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.utils.Serialization; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.api.reconciler.dependent.StandaloneKubernetesDependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; import io.javaoperatorsdk.operator.junit.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.source.EventSource; @@ -23,11 +23,11 @@ public class StandaloneDependentTestReconciler private KubernetesClient kubernetesClient; - StandaloneKubernetesDependentResource configMapDependent; + KubernetesDependentResource configMapDependent; public StandaloneDependentTestReconciler() { configMapDependent = - new StandaloneKubernetesDependentResource<>(Deployment.class, (primary, context) -> { + new KubernetesDependentResource<>(Deployment.class, (primary, context) -> { Deployment deployment = loadYaml(Deployment.class, "nginx-deployment.yaml"); deployment.getMetadata().setName(primary.getMetadata().getName()); deployment.getMetadata().setNamespace(primary.getMetadata().getNamespace()); diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java index 28d6ed3037..e6fa660e26 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java @@ -15,7 +15,7 @@ import io.fabric8.kubernetes.client.utils.Serialization; import io.javaoperatorsdk.operator.api.reconciler.*; import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.dependent.StandaloneKubernetesDependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.EventSource; @@ -30,9 +30,9 @@ public class WebPageReconciler private final KubernetesClient kubernetesClient; - private StandaloneKubernetesDependentResource configMapDR; - private StandaloneKubernetesDependentResource deploymentDR; - private StandaloneKubernetesDependentResource serviceDR; + private KubernetesDependentResource configMapDR; + private KubernetesDependentResource deploymentDR; + private KubernetesDependentResource serviceDR; public WebPageReconciler(KubernetesClient kubernetesClient) { this.kubernetesClient = kubernetesClient; @@ -84,7 +84,7 @@ public Optional updateErrorStatus( private void createDependentResources(KubernetesClient client) { this.configMapDR = - new StandaloneKubernetesDependentResource<>( + new KubernetesDependentResource<>( client, ConfigMap.class, (WebPage webPage, Context context) -> { @@ -123,7 +123,7 @@ protected ConfigMap update( primary -> new ResourceID(configMapName(primary), primary.getMetadata().getNamespace())); this.deploymentDR = - new StandaloneKubernetesDependentResource<>( + new KubernetesDependentResource<>( client, Deployment.class, (webPage, context) -> { @@ -157,7 +157,7 @@ protected boolean match(Deployment actual, Deployment target, Context context) { }; this.serviceDR = - new StandaloneKubernetesDependentResource<>( + new KubernetesDependentResource<>( client, Service.class, (webPage, context) -> { From 55ad55d8f4bcf4d0fdaf21aaffea6db16114cdb7 Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 11 Feb 2022 14:53:52 +0100 Subject: [PATCH 03/10] fix: kubernetes client aware --- .../api/reconciler/dependent/KubernetesClientAware.java | 7 +++++++ .../reconciler/dependent/KubernetesDependentResource.java | 7 +++---- .../dependent/DependentResourceInitializer.java | 8 +++++++- .../dependent/KubernetesDependentResourceInitializer.java | 2 -- .../StandaloneDependentTestReconciler.java | 2 +- 5 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesClientAware.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesClientAware.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesClientAware.java new file mode 100644 index 0000000000..b8ef888ec3 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesClientAware.java @@ -0,0 +1,7 @@ +package io.javaoperatorsdk.operator.api.reconciler.dependent; + +import io.fabric8.kubernetes.client.KubernetesClient; + +public interface KubernetesClientAware { + void setKubernetesClient(KubernetesClient kubernetesClient); +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java index 254bd8ee7e..fd14d9b4ec 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -20,7 +20,7 @@ import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; public abstract class KubernetesDependentResource - extends AbstractDependentResource { + extends AbstractDependentResource implements KubernetesClientAware { private static final Logger log = LoggerFactory.getLogger(KubernetesDependentResource.class); @@ -151,12 +151,11 @@ public Optional getResource(P primaryResource) { return informerEventSource.getAssociated(primaryResource); } - public KubernetesDependentResource setClient(KubernetesClient client) { + @Override + public void setKubernetesClient(KubernetesClient client) { this.client = client; - return this; } - public KubernetesDependentResource setExplicitDelete(boolean explicitDelete) { this.explicitDelete = explicitDelete; return this; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java index a00e5b47bf..aa90a822de 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java @@ -5,12 +5,18 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesClientAware; public class DependentResourceInitializer, K extends DependentResourceConfiguration> { public T initDependentResource(K config, KubernetesClient kubernetesClient) { try { - return (T) config.getDependentResourceClass().getConstructor().newInstance(); + DependentResource dependentResource = + config.getDependentResourceClass().getConstructor().newInstance(); + if (dependentResource instanceof KubernetesClientAware) { + ((KubernetesClientAware) dependentResource).setKubernetesClient(kubernetesClient); + } + return (T) dependentResource; } catch (InstantiationException | IllegalAccessException | InvocationTargetException diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java index eb544c76e9..c224af3df9 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java @@ -12,10 +12,8 @@ public class KubernetesDependentResourceInitializer extends KubernetesDependentResourceConfiguration config, KubernetesClient client) { - // todo with constructor, require a specific constructor args ?! KubernetesDependentResource kubernetesDependentResource = super.initDependentResource(config, client); - kubernetesDependentResource.setClient(client); kubernetesDependentResource.initWithConfiguration(config); return kubernetesDependentResource; } 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 337b619af2..86ab2f8990 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 @@ -59,7 +59,7 @@ public UpdateControl reconcile( @Override public void setKubernetesClient(KubernetesClient kubernetesClient) { this.kubernetesClient = kubernetesClient; - configMapDependent.setClient(kubernetesClient); + configMapDependent.setKubernetesClient(kubernetesClient); } @Override From 1c430e45e4a8b77fc1f58cefbab5fc166d230423 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Fri, 11 Feb 2022 15:14:09 +0100 Subject: [PATCH 04/10] refactor: remove unneeded overrides --- ...ernetesDependentResourceConfiguration.java | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java index 6c0f8b3067..f76be0c8b6 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java @@ -12,11 +12,12 @@ public interface KubernetesDependentResourceConfiguration extends DependentResourceConfiguration, ResourceConfiguration { - @Override - ConfigurationService getConfigurationService(); + boolean isOwned(); @Override - void setConfigurationService(ConfigurationService service); + default Class getResourceClass() { + return ResourceConfiguration.super.getResourceClass(); + } class DefaultKubernetesDependentResourceConfiguration extends DefaultResourceConfiguration @@ -48,22 +49,13 @@ public Class> getDependentResourceClass() { } } + @SuppressWarnings({"rawtypes", "unchecked"}) static KubernetesDependentResourceConfiguration from( InformerConfiguration cfg, boolean owned, Class dependentResourceClass) { - return new DefaultKubernetesDependentResourceConfiguration(cfg.getConfigurationService(), + return new DefaultKubernetesDependentResourceConfiguration<>(cfg.getConfigurationService(), cfg.getLabelSelector(), cfg.getResourceClass(), cfg.getNamespaces(), owned, (Class>) dependentResourceClass); } - - Class> getDependentResourceClass(); - - @Override - default Class getResourceClass() { - return null; - } - - boolean isOwned(); - } From e0a2f484b993dd081b0f5c2608700f9f39f98312 Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Fri, 11 Feb 2022 15:20:13 +0100 Subject: [PATCH 05/10] docs: clean-up javadoc --- .../api/reconciler/ControllerConfiguration.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java index 0c9276211e..0b0a2a3fd5 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java @@ -50,21 +50,27 @@ */ String labelSelector() default Constants.EMPTY_STRING; - /** * Optional list of classes providing custom {@link ResourceEventFilter}. * * @return the list of event filters. */ - @SuppressWarnings("rawtypes") Class[] eventFilters() default {}; + /** + * Optional configuration of the maximal interval the SDK will wait for a reconciliation request + * to happen before one will be automatically triggered. + * + * @return the maximal interval configuration + */ ReconciliationMaxInterval reconciliationMaxInterval() default @ReconciliationMaxInterval( - interval = 10, timeUnit = TimeUnit.HOURS); - + interval = 10); /** - * @return the list of {@link DependentResourceController} implementations + * Optional list of {@link Dependent} configurations which associate a resource type to a + * {@link io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource} implementation + * + * @return the list of {@link Dependent} configurations */ Dependent[] dependents() default {}; } From f79c0ce92a1b23f12e22b47992dc22c69184e1d0 Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 11 Feb 2022 15:52:07 +0100 Subject: [PATCH 06/10] fix: refactor fix e2e tests --- .../KubernetesDependentResource.java | 11 ++++ .../dependent/DependentResourceManager.java | 2 +- .../sample/SecretDependentResource.java | 15 +++-- .../sample/DeploymentDependentResource.java | 60 +++++++++---------- .../sample/ServiceDependentResource.java | 28 ++++----- 5 files changed, 62 insertions(+), 54 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java index fd14d9b4ec..4df1536c81 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -199,4 +199,15 @@ public KubernetesDependentResource setPrimaryResourcesRetriever( this.primaryResourcesRetriever = primaryResourcesRetriever; return this; } + + public KubernetesDependentResource setDesiredSupplier( + DesiredSupplier desiredSupplier) { + this.desiredSupplier = desiredSupplier; + return this; + } + + public KubernetesDependentResource setResourceType(Class resourceType) { + this.resourceType = resourceType; + return this; + } } 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 index 88afc1fbd3..d659a8348e 100644 --- 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 @@ -90,7 +90,7 @@ private void initContextIfNeeded(P resource, Context context) { private DependentResource from(DependentResourceConfiguration config, KubernetesClient client) { if (config instanceof KubernetesDependentResourceConfiguration) { - if (config.getDependentResourceClass().isAssignableFrom(KubernetesDependentResource.class)) { + if (KubernetesDependentResource.class.isAssignableFrom(config.getDependentResourceClass())) { KubernetesDependentResourceInitializer dependentResourceInitializer = new KubernetesDependentResourceInitializer(); return dependentResourceInitializer diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java index 4f6bd1759c..a6aa54d2fc 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java @@ -14,13 +14,8 @@ public class SecretDependentResource extends KubernetesDependentResource implements AssociatedSecondaryResourceIdentifier { - private static String encode(String value) { - return Base64.getEncoder().encodeToString(value.getBytes()); - } - - @Override - public Secret desired(MySQLSchema schema, Context context) { - return new SecretBuilder() + public SecretDependentResource() { + setDesiredSupplier((schema, context) -> new SecretBuilder() .withNewMetadata() .withName(context.getMandatory(MYSQL_SECRET_NAME, String.class)) .withNamespace(schema.getMetadata().getNamespace()) @@ -29,7 +24,11 @@ public Secret desired(MySQLSchema schema, Context context) { "MYSQL_USERNAME", encode(context.getMandatory(MYSQL_SECRET_USERNAME, String.class))) .addToData( "MYSQL_PASSWORD", encode(context.getMandatory(MYSQL_SECRET_PASSWORD, String.class))) - .build(); + .build()); + } + + private static String encode(String value) { + return Base64.getEncoder().encodeToString(value.getBytes()); } // An alternative would be to override reconcile() method and exclude the update part. diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java index b681ccf6b6..5a1874e6dc 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java @@ -11,38 +11,38 @@ public class DeploymentDependentResource extends KubernetesDependentResource { - public DeploymentDependentResource() {} - - @Override - public Deployment desired(Tomcat tomcat, Context context) { - Deployment deployment = TomcatReconciler.loadYaml(Deployment.class, "deployment.yaml"); - final ObjectMeta tomcatMetadata = tomcat.getMetadata(); - final String tomcatName = tomcatMetadata.getName(); - deployment = new DeploymentBuilder(deployment) - .editMetadata() - .withName(tomcatName) - .withNamespace(tomcatMetadata.getNamespace()) - .addToLabels("app", tomcatName) - .addToLabels("app.kubernetes.io/part-of", tomcatName) - .addToLabels("app.kubernetes.io/managed-by", "tomcat-operator") - .endMetadata() - .editSpec() - .editSelector().addToMatchLabels("app", tomcatName).endSelector() - .withReplicas(tomcat.getSpec().getReplicas()) - // set tomcat version - .editTemplate() - // make sure label selector matches label (which has to be matched by service selector too) - .editMetadata().addToLabels("app", tomcatName).endMetadata() - .editSpec() - .editFirstContainer().withImage(tomcatImage(tomcat)).endContainer() - .endSpec() - .endTemplate() - .endSpec() - .build(); - return deployment; + public DeploymentDependentResource() { + super(Deployment.class, (tomcat, context) -> { + Deployment deployment = TomcatReconciler.loadYaml(Deployment.class, "deployment.yaml"); + final ObjectMeta tomcatMetadata = tomcat.getMetadata(); + final String tomcatName = tomcatMetadata.getName(); + deployment = new DeploymentBuilder(deployment) + .editMetadata() + .withName(tomcatName) + .withNamespace(tomcatMetadata.getNamespace()) + .addToLabels("app", tomcatName) + .addToLabels("app.kubernetes.io/part-of", tomcatName) + .addToLabels("app.kubernetes.io/managed-by", "tomcat-operator") + .endMetadata() + .editSpec() + .editSelector().addToMatchLabels("app", tomcatName).endSelector() + .withReplicas(tomcat.getSpec().getReplicas()) + // set tomcat version + .editTemplate() + // make sure label selector matches label (which has to be matched by service selector + // too) + .editMetadata().addToLabels("app", tomcatName).endMetadata() + .editSpec() + .editFirstContainer().withImage(tomcatImage(tomcat)).endContainer() + .endSpec() + .endTemplate() + .endSpec() + .build(); + return deployment; + }); } - private String tomcatImage(Tomcat tomcat) { + 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 16a6aaff2e..4a43508139 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 @@ -3,24 +3,22 @@ import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServiceBuilder; -import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; public class ServiceDependentResource extends KubernetesDependentResource { - public ServiceDependentResource() {} - - @Override - public Service desired(Tomcat tomcat, Context context) { - final ObjectMeta tomcatMetadata = tomcat.getMetadata(); - return new ServiceBuilder(TomcatReconciler.loadYaml(Service.class, "service.yaml")) - .editMetadata() - .withName(tomcatMetadata.getName()) - .withNamespace(tomcatMetadata.getNamespace()) - .endMetadata() - .editSpec() - .addToSelector("app", tomcatMetadata.getName()) - .endSpec() - .build(); + public ServiceDependentResource() { + super(Service.class, (tomcat, context) -> { + final ObjectMeta tomcatMetadata = tomcat.getMetadata(); + return new ServiceBuilder(TomcatReconciler.loadYaml(Service.class, "service.yaml")) + .editMetadata() + .withName(tomcatMetadata.getName()) + .withNamespace(tomcatMetadata.getNamespace()) + .endMetadata() + .editSpec() + .addToSelector("app", tomcatMetadata.getName()) + .endSpec() + .build(); + }); } } From 82483d009b27608339bf7a8901194f8d9d092735 Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 11 Feb 2022 15:58:19 +0100 Subject: [PATCH 07/10] fix: format --- .../operator/api/reconciler/ControllerConfiguration.java | 1 - 1 file changed, 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java index 0b0a2a3fd5..6d964e26ad 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java @@ -4,7 +4,6 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.util.concurrent.TimeUnit; import io.javaoperatorsdk.operator.api.config.dependent.Dependent; import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter; From f45afb152c363e11ee4627e8b75a87e631ddd3ed Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 11 Feb 2022 16:47:29 +0100 Subject: [PATCH 08/10] fix: mysql e2e test --- .../sample/SecretDependentResource.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java index a6aa54d2fc..6733db0161 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java @@ -15,16 +15,17 @@ public class SecretDependentResource extends KubernetesDependentResource { public SecretDependentResource() { - setDesiredSupplier((schema, context) -> new SecretBuilder() - .withNewMetadata() - .withName(context.getMandatory(MYSQL_SECRET_NAME, String.class)) - .withNamespace(schema.getMetadata().getNamespace()) - .endMetadata() - .addToData( - "MYSQL_USERNAME", encode(context.getMandatory(MYSQL_SECRET_USERNAME, String.class))) - .addToData( - "MYSQL_PASSWORD", encode(context.getMandatory(MYSQL_SECRET_PASSWORD, String.class))) - .build()); + super(Secret.class, + (schema, context) -> new SecretBuilder() + .withNewMetadata() + .withName(context.getMandatory(MYSQL_SECRET_NAME, String.class)) + .withNamespace(schema.getMetadata().getNamespace()) + .endMetadata() + .addToData( + "MYSQL_USERNAME", encode(context.getMandatory(MYSQL_SECRET_USERNAME, String.class))) + .addToData( + "MYSQL_PASSWORD", encode(context.getMandatory(MYSQL_SECRET_PASSWORD, String.class))) + .build()); } private static String encode(String value) { From 6e2153f65fa3a22001b66768a48536df040d3efc Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Mon, 14 Feb 2022 10:46:08 +0100 Subject: [PATCH 09/10] Further configuration polish (#927) * refactor: DependentResourceManager now configures DependentResources This makes it possible to pass a configuration DependentResource implementations and removes the need to initializers. * refactor: remove DesiredSupplier since it makes things less readable --- .../DependentResourceConfiguration.java | 2 +- ...ernetesDependentResourceConfiguration.java | 8 +- .../dependent/AbstractDependentResource.java | 5 +- .../dependent/DependentResource.java | 4 +- .../reconciler/dependent/DesiredSupplier.java | 10 -- .../KubernetesDependentResource.java | 154 ++++------------- .../operator/processing/Controller.java | 2 +- .../DependentResourceInitializer.java | 27 --- .../dependent/DependentResourceManager.java | 67 ++++---- ...ubernetesDependentResourceInitializer.java | 21 --- .../StandaloneDependentTestReconciler.java | 37 ++-- .../sample/SchemaDependentResource.java | 4 +- .../sample/SecretDependentResource.java | 28 +-- .../sample/DeploymentDependentResource.java | 64 ++++--- .../sample/ServiceDependentResource.java | 26 +-- .../operator/sample/WebPageReconciler.java | 162 +++++++++--------- 16 files changed, 245 insertions(+), 376 deletions(-) delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredSupplier.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceConfiguration.java index c0f428c12d..04c80d6413 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceConfiguration.java @@ -5,7 +5,7 @@ public interface DependentResourceConfiguration { - Class> getDependentResourceClass(); + Class>> getDependentResourceClass(); Class getResourceClass(); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java index f76be0c8b6..f38d0b0c93 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java @@ -24,14 +24,14 @@ class DefaultKubernetesDependentResourceConfiguration { - private final Class> dependentResourceClass; + private final Class>> dependentResourceClass; private final boolean owned; protected DefaultKubernetesDependentResourceConfiguration( ConfigurationService configurationService, String labelSelector, Class resourceClass, Set namespaces, boolean owned, - Class> dependentResourceClass) { + Class>> dependentResourceClass) { super(labelSelector, resourceClass, namespaces); setConfigurationService(configurationService); this.owned = owned; @@ -44,7 +44,7 @@ public boolean isOwned() { } @Override - public Class> getDependentResourceClass() { + public Class>> getDependentResourceClass() { return dependentResourceClass; } } @@ -56,6 +56,6 @@ static KubernetesDependentResourc return new DefaultKubernetesDependentResourceConfiguration<>(cfg.getConfigurationService(), cfg.getLabelSelector(), cfg.getResourceClass(), cfg.getNamespaces(), owned, - (Class>) dependentResourceClass); + (Class>>) dependentResourceClass); } } 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 ea8b8bc06b..74df7e7960 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 @@ -1,10 +1,11 @@ package io.javaoperatorsdk.operator.api.reconciler.dependent; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; -public abstract class AbstractDependentResource - implements DependentResource { +public abstract class AbstractDependentResource> + implements DependentResource { @Override public void reconcile(P primary, Context context) { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java index b097554107..01cdb66b60 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java @@ -4,11 +4,12 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.config.Utils; +import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.processing.event.source.EventSource; -public interface DependentResource { +public interface DependentResource> { Optional eventSource(EventSourceContext

context); @@ -23,4 +24,5 @@ default Class resourceType() { Optional getResource(P primaryResource); + default void configureWith(C config) {} } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredSupplier.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredSupplier.java deleted file mode 100644 index b93d75950b..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DesiredSupplier.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.javaoperatorsdk.operator.api.reconciler.dependent; - -import io.javaoperatorsdk.operator.api.reconciler.Context; - -@FunctionalInterface -public interface DesiredSupplier { - - R getDesired(P primary, Context context); - -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java index 4df1536c81..ac35cc2441 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java @@ -1,6 +1,7 @@ package io.javaoperatorsdk.operator.api.reconciler.dependent; import java.util.Optional; +import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -8,6 +9,8 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.ReconcilerUtils; +import io.javaoperatorsdk.operator.api.config.ConfigurationService; +import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependent; import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependentResourceConfiguration; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; @@ -20,55 +23,43 @@ import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; public abstract class KubernetesDependentResource - extends AbstractDependentResource implements KubernetesClientAware { + extends AbstractDependentResource> + implements KubernetesClientAware { private static final Logger log = LoggerFactory.getLogger(KubernetesDependentResource.class); protected KubernetesClient client; - private boolean explicitDelete = false; - private boolean owned = true; private InformerEventSource informerEventSource; - private DesiredSupplier desiredSupplier = null; - private Class resourceType = null; - private AssociatedSecondaryResourceIdentifier

associatedSecondaryResourceIdentifier = - ResourceID::fromResource; - private PrimaryResourcesRetriever primaryResourcesRetriever = Mappers.fromOwnerReference(); - - public KubernetesDependentResource() { - this(null); - } - - public KubernetesDependentResource(KubernetesClient client) { - this.client = client; - } - - public KubernetesDependentResource( - KubernetesClient client, Class resourceType, DesiredSupplier desiredSupplier) { - this.client = client; - this.resourceType = resourceType; - this.desiredSupplier = desiredSupplier; - } + private KubernetesDependentResourceConfiguration configuration; - public KubernetesDependentResource( - Class resourceType, DesiredSupplier desiredSupplier) { - this(null, resourceType, desiredSupplier); + public void configureWith(KubernetesDependentResourceConfiguration config) { + configureWith(config.getConfigurationService(), config.getLabelSelector(), + config.getNamespaces(), config.isOwned()); } - // todo builder and/or factory methods - public void initWithConfiguration(KubernetesDependentResourceConfiguration config) { - this.owned = config.isOwned(); + @SuppressWarnings("unchecked") + private void configureWith(ConfigurationService service, String labelSelector, + Set namespaces, boolean owned) { + final var primaryResourcesRetriever = + (this instanceof PrimaryResourcesRetriever) ? (PrimaryResourcesRetriever) this + : Mappers.fromOwnerReference(); + final AssociatedSecondaryResourceIdentifier

secondaryResourceIdentifier = + (this instanceof AssociatedSecondaryResourceIdentifier) + ? (AssociatedSecondaryResourceIdentifier

) this + : ResourceID::fromResource; InformerConfiguration ic = - InformerConfiguration.from(config.getConfigurationService(), resourceType()) - .withLabelSelector(config.getLabelSelector()) - .withNamespaces(config.getNamespaces()) - .withPrimaryResourcesRetriever(getPrimaryResourcesRetriever()) - .withAssociatedSecondaryResourceIdentifier(getAssociatedSecondaryResourceIdentifier()) + InformerConfiguration.from(service, resourceType()) + .withLabelSelector(labelSelector) + .withNamespaces(namespaces) + .withPrimaryResourcesRetriever(primaryResourcesRetriever) + .withAssociatedSecondaryResourceIdentifier(secondaryResourceIdentifier) .build(); + configuration = KubernetesDependentResourceConfiguration.from(ic, owned, getClass()); informerEventSource = new InformerEventSource<>(ic, client); } protected void beforeCreateOrUpdate(R desired, P primary) { - if (owned) { + if (configuration.isOwned()) { desired.addOwnerReference(primary); } } @@ -100,38 +91,17 @@ protected R update(R actual, R target, P primary, Context context) { .replace(target); } - @SuppressWarnings({"unchecked", "rawtypes"}) @Override public Optional eventSource(EventSourceContext

context) { - if (informerEventSource != null) { - return Optional.of(informerEventSource); + if (informerEventSource == null) { + configureWith(context.getConfigurationService(), null, null, + KubernetesDependent.OWNED_DEFAULT); + log.warn("Using default configuration for " + resourceType().getSimpleName() + + " KubernetesDependentResource, call configureWith to provide configuration"); } - var informerConfig = initDefaultInformerConfiguration(context); - informerEventSource = new InformerEventSource(informerConfig, context); return Optional.of(informerEventSource); } - @SuppressWarnings("unchecked") - private InformerConfiguration initDefaultInformerConfiguration( - EventSourceContext

context) { - return InformerConfiguration.from(context, resourceType()) - .withPrimaryResourcesRetriever(getPrimaryResourcesRetriever()) - .withAssociatedSecondaryResourceIdentifier(getAssociatedSecondaryResourceIdentifier()) - .build(); - } - - - protected PrimaryResourcesRetriever getPrimaryResourcesRetriever() { - return (this instanceof PrimaryResourcesRetriever) ? (PrimaryResourcesRetriever) this - : primaryResourcesRetriever; - } - - protected AssociatedSecondaryResourceIdentifier

getAssociatedSecondaryResourceIdentifier() { - return (this instanceof AssociatedSecondaryResourceIdentifier) - ? (AssociatedSecondaryResourceIdentifier

) this - : associatedSecondaryResourceIdentifier; - } - public KubernetesDependentResource setInformerEventSource( InformerEventSource informerEventSource) { this.informerEventSource = informerEventSource; @@ -140,10 +110,9 @@ public KubernetesDependentResource setInformerEventSource( @Override public void delete(P primary, Context context) { - if (explicitDelete) { - var resource = getResource(primary); - resource.ifPresent(r -> client.resource(r).delete()); - } + // todo: do we need explicit delete? If yes, add it to configuration + var resource = getResource(primary); + resource.ifPresent(r -> client.resource(r).delete()); } @Override @@ -155,59 +124,4 @@ public Optional getResource(P primaryResource) { public void setKubernetesClient(KubernetesClient client) { this.client = client; } - - public KubernetesDependentResource setExplicitDelete(boolean explicitDelete) { - this.explicitDelete = explicitDelete; - return this; - } - - public boolean isExplicitDelete() { - return explicitDelete; - } - - public boolean isOwned() { - return owned; - } - - public KubernetesDependentResource setOwned(boolean owned) { - this.owned = owned; - return this; - } - - @Override - public Class resourceType() { - if (resourceType != null) { - return resourceType; - } else { - return super.resourceType(); - } - } - - @Override - protected R desired(P primary, Context context) { - return desiredSupplier.getDesired(primary, context); - } - - public KubernetesDependentResource setAssociatedSecondaryResourceIdentifier( - AssociatedSecondaryResourceIdentifier

associatedSecondaryResourceIdentifier) { - this.associatedSecondaryResourceIdentifier = associatedSecondaryResourceIdentifier; - return this; - } - - public KubernetesDependentResource setPrimaryResourcesRetriever( - PrimaryResourcesRetriever primaryResourcesRetriever) { - this.primaryResourcesRetriever = primaryResourcesRetriever; - return this; - } - - public KubernetesDependentResource setDesiredSupplier( - DesiredSupplier desiredSupplier) { - this.desiredSupplier = desiredSupplier; - return this; - } - - public KubernetesDependentResource setResourceType(Class resourceType) { - this.resourceType = resourceType; - return this; - } } 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 d0c86475d3..f3ad2dd8ec 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 @@ -56,7 +56,7 @@ public Controller(Reconciler reconciler, this.kubernetesClient = kubernetesClient; eventSourceManager = new EventSourceManager<>(this); - dependents = new DependentResourceManager<>(this, kubernetesClient); + dependents = new DependentResourceManager<>(this); } @Override diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java deleted file mode 100644 index aa90a822de..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/DependentResourceInitializer.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent; - -import java.lang.reflect.InvocationTargetException; - -import io.fabric8.kubernetes.client.KubernetesClient; -import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; -import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesClientAware; - -public class DependentResourceInitializer, K extends DependentResourceConfiguration> { - - public T initDependentResource(K config, KubernetesClient kubernetesClient) { - try { - DependentResource dependentResource = - config.getDependentResourceClass().getConstructor().newInstance(); - if (dependentResource instanceof KubernetesClientAware) { - ((KubernetesClientAware) dependentResource).setKubernetesClient(kubernetesClient); - } - return (T) dependentResource; - } catch (InstantiationException - | IllegalAccessException - | InvocationTargetException - | NoSuchMethodException e) { - throw new IllegalStateException(e); - } - } -} 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 index d659a8348e..3e1d1c9f0a 100644 --- 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 @@ -1,13 +1,14 @@ 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 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.DependentResourceConfiguration; -import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependentResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.ContextInitializer; import io.javaoperatorsdk.operator.api.reconciler.DeleteControl; @@ -18,7 +19,7 @@ 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.KubernetesDependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.Controller; import io.javaoperatorsdk.operator.processing.event.source.EventSource; @@ -30,30 +31,25 @@ public class DependentResourceManager

implements EventSou private final ControllerConfiguration

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

controller, KubernetesClient kubernetesClient) { + public DependentResourceManager(Controller

controller) { this.reconciler = controller.getReconciler(); this.controllerConfiguration = controller.getConfiguration(); - initDependentResourceControllers(kubernetesClient); - } - - private void initDependentResourceControllers(KubernetesClient kubernetesClient) { - final List dependentResourceConfigurations = - controllerConfiguration.getDependentResources(); - dependents = new ArrayList<>(dependentResourceConfigurations.size()); - dependentResourceConfigurations.forEach(dependent -> { - final var dependentResourceController = from(dependent, kubernetesClient); - dependents.add(dependentResourceController); - }); } @Override public List prepareEventSources(EventSourceContext

context) { - List sources = new ArrayList<>(); - dependents.forEach(dependent -> { - dependent.eventSource(context) - .ifPresent(es -> sources.add((EventSource) es)); - }); + final var dependentConfigurations = controllerConfiguration.getDependentResources(); + final var sources = new ArrayList(dependentConfigurations.size()); + + dependents = dependentConfigurations.stream() + .map(drc -> { + final var dependentResource = from(drc, context.getClient()); + dependentResource.eventSource(context) + .ifPresent(es -> sources.add((EventSource) es)); + return dependentResource; + }) + .collect(Collectors.toList()); + return sources; } @@ -87,23 +83,22 @@ private void initContextIfNeeded(P resource, Context context) { } } - private DependentResource from(DependentResourceConfiguration config, - KubernetesClient client) { - if (config instanceof KubernetesDependentResourceConfiguration) { - if (KubernetesDependentResource.class.isAssignableFrom(config.getDependentResourceClass())) { - KubernetesDependentResourceInitializer dependentResourceInitializer = - new KubernetesDependentResourceInitializer(); - return dependentResourceInitializer - .initDependentResource((KubernetesDependentResourceConfiguration) config, client); - } else { - throw new IllegalArgumentException("A " - + KubernetesDependentResourceConfiguration.class.getCanonicalName() - + " must be associated to a " + KubernetesDependentResource.class.getCanonicalName()); + private DependentResource from(DependentResourceConfiguration config, KubernetesClient client) { + try { + final var dependentResource = + (DependentResource) config.getDependentResourceClass().getConstructor().newInstance(); + if (dependentResource instanceof KubernetesClientAware) { + ((KubernetesClientAware) dependentResource).setKubernetesClient(client); } - } else { - DependentResourceInitializer dependentResourceInitializer = - new DependentResourceInitializer(); - return dependentResourceInitializer.initDependentResource(config, client); + + dependentResource.configureWith(config); + + return dependentResource; + } catch (InstantiationException + | IllegalAccessException + | InvocationTargetException + | NoSuchMethodException e) { + throw new IllegalStateException(e); } } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java deleted file mode 100644 index c224af3df9..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/KubernetesDependentResourceInitializer.java +++ /dev/null @@ -1,21 +0,0 @@ -package io.javaoperatorsdk.operator.processing.dependent; - -import io.fabric8.kubernetes.client.KubernetesClient; -import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependentResourceConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; - -public class KubernetesDependentResourceInitializer extends - DependentResourceInitializer, KubernetesDependentResourceConfiguration> { - - @Override - public KubernetesDependentResource initDependentResource( - KubernetesDependentResourceConfiguration config, - KubernetesClient client) { - - KubernetesDependentResource kubernetesDependentResource = - super.initDependentResource(config, client); - kubernetesDependentResource.initWithConfiguration(config); - return kubernetesDependentResource; - } - -} 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 86ab2f8990..44be1721b3 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 @@ -26,21 +26,7 @@ public class StandaloneDependentTestReconciler KubernetesDependentResource configMapDependent; public StandaloneDependentTestReconciler() { - configMapDependent = - new KubernetesDependentResource<>(Deployment.class, (primary, context) -> { - Deployment deployment = loadYaml(Deployment.class, "nginx-deployment.yaml"); - deployment.getMetadata().setName(primary.getMetadata().getName()); - deployment.getMetadata().setNamespace(primary.getMetadata().getNamespace()); - return deployment; - }) { - @Override - protected boolean match(Deployment actual, Deployment target, Context context) { - return Objects.equals(actual.getSpec().getReplicas(), target.getSpec().getReplicas()) && - actual.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() - .equals( - target.getSpec().getTemplate().getSpec().getContainers().get(0).getImage()); - } - }; + configMapDependent = new DeploymentDependentResource(); } @Override @@ -74,4 +60,25 @@ private T loadYaml(Class clazz, String yaml) { throw new IllegalStateException("Cannot find yaml on classpath: " + yaml); } } + + private class DeploymentDependentResource extends + KubernetesDependentResource { + + @Override + protected Deployment desired(StandaloneDependentTestCustomResource primary, Context context) { + Deployment deployment = StandaloneDependentTestReconciler.this.loadYaml(Deployment.class, + "nginx-deployment.yaml"); + deployment.getMetadata().setName(primary.getMetadata().getName()); + deployment.getMetadata().setNamespace(primary.getMetadata().getNamespace()); + return deployment; + } + + @Override + protected boolean match(Deployment actual, Deployment target, Context context) { + return Objects.equals(actual.getSpec().getReplicas(), target.getSpec().getReplicas()) && + actual.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() + .equals( + target.getSpec().getTemplate().getSpec().getContainers().get(0).getImage()); + } + } } diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java index 957f0b34ff..1e0de2393a 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java @@ -5,6 +5,7 @@ import java.sql.SQLException; import java.util.Optional; +import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.dependent.AbstractDependentResource; @@ -15,7 +16,8 @@ import static java.lang.String.format; -public class SchemaDependentResource extends AbstractDependentResource { +public class SchemaDependentResource extends + AbstractDependentResource> { private static final int POLL_PERIOD = 500; private MySQLDbConfig dbConfig; diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java index 6733db0161..475aa1783e 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java @@ -14,20 +14,6 @@ public class SecretDependentResource extends KubernetesDependentResource implements AssociatedSecondaryResourceIdentifier { - public SecretDependentResource() { - super(Secret.class, - (schema, context) -> new SecretBuilder() - .withNewMetadata() - .withName(context.getMandatory(MYSQL_SECRET_NAME, String.class)) - .withNamespace(schema.getMetadata().getNamespace()) - .endMetadata() - .addToData( - "MYSQL_USERNAME", encode(context.getMandatory(MYSQL_SECRET_USERNAME, String.class))) - .addToData( - "MYSQL_PASSWORD", encode(context.getMandatory(MYSQL_SECRET_PASSWORD, String.class))) - .build()); - } - private static String encode(String value) { return Base64.getEncoder().encodeToString(value.getBytes()); } @@ -40,6 +26,20 @@ protected Secret update(Secret actual, Secret target, MySQLSchema primary, Conte + primary); } + @Override + protected Secret desired(MySQLSchema schema, Context context) { + return new SecretBuilder() + .withNewMetadata() + .withName(context.getMandatory(MYSQL_SECRET_NAME, String.class)) + .withNamespace(schema.getMetadata().getNamespace()) + .endMetadata() + .addToData( + "MYSQL_USERNAME", encode(context.getMandatory(MYSQL_SECRET_USERNAME, String.class))) + .addToData( + "MYSQL_PASSWORD", encode(context.getMandatory(MYSQL_SECRET_PASSWORD, String.class))) + .build(); + } + @Override protected boolean match(Secret actual, Secret target, Context context) { return ResourceID.fromResource(actual).equals(ResourceID.fromResource(target)); diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java index 5a1874e6dc..620e908fea 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java @@ -8,44 +8,42 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; @KubernetesDependent(labelSelector = "app.kubernetes.io/managed-by=tomcat-operator") -public class DeploymentDependentResource - extends KubernetesDependentResource { - - public DeploymentDependentResource() { - super(Deployment.class, (tomcat, context) -> { - Deployment deployment = TomcatReconciler.loadYaml(Deployment.class, "deployment.yaml"); - final ObjectMeta tomcatMetadata = tomcat.getMetadata(); - final String tomcatName = tomcatMetadata.getName(); - deployment = new DeploymentBuilder(deployment) - .editMetadata() - .withName(tomcatName) - .withNamespace(tomcatMetadata.getNamespace()) - .addToLabels("app", tomcatName) - .addToLabels("app.kubernetes.io/part-of", tomcatName) - .addToLabels("app.kubernetes.io/managed-by", "tomcat-operator") - .endMetadata() - .editSpec() - .editSelector().addToMatchLabels("app", tomcatName).endSelector() - .withReplicas(tomcat.getSpec().getReplicas()) - // set tomcat version - .editTemplate() - // make sure label selector matches label (which has to be matched by service selector - // too) - .editMetadata().addToLabels("app", tomcatName).endMetadata() - .editSpec() - .editFirstContainer().withImage(tomcatImage(tomcat)).endContainer() - .endSpec() - .endTemplate() - .endSpec() - .build(); - return deployment; - }); - } +public class DeploymentDependentResource extends KubernetesDependentResource { private static String tomcatImage(Tomcat tomcat) { return "tomcat:" + tomcat.getSpec().getVersion(); } + @Override + protected Deployment desired(Tomcat tomcat, Context context) { + Deployment deployment = TomcatReconciler.loadYaml(Deployment.class, "deployment.yaml"); + final ObjectMeta tomcatMetadata = tomcat.getMetadata(); + final String tomcatName = tomcatMetadata.getName(); + deployment = new DeploymentBuilder(deployment) + .editMetadata() + .withName(tomcatName) + .withNamespace(tomcatMetadata.getNamespace()) + .addToLabels("app", tomcatName) + .addToLabels("app.kubernetes.io/part-of", tomcatName) + .addToLabels("app.kubernetes.io/managed-by", "tomcat-operator") + .endMetadata() + .editSpec() + .editSelector().addToMatchLabels("app", tomcatName).endSelector() + .withReplicas(tomcat.getSpec().getReplicas()) + // set tomcat version + .editTemplate() + // make sure label selector matches label (which has to be matched by service selector + // too) + .editMetadata().addToLabels("app", tomcatName).endMetadata() + .editSpec() + .editFirstContainer().withImage(tomcatImage(tomcat)).endContainer() + .endSpec() + .endTemplate() + .endSpec() + .build(); + return deployment; + } + @Override public boolean match(Deployment fetched, Deployment target, Context context) { return fetched.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() 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 4a43508139..e2fdb3f026 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 @@ -3,22 +3,22 @@ import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServiceBuilder; +import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; public class ServiceDependentResource extends KubernetesDependentResource { - public ServiceDependentResource() { - super(Service.class, (tomcat, context) -> { - final ObjectMeta tomcatMetadata = tomcat.getMetadata(); - return new ServiceBuilder(TomcatReconciler.loadYaml(Service.class, "service.yaml")) - .editMetadata() - .withName(tomcatMetadata.getName()) - .withNamespace(tomcatMetadata.getNamespace()) - .endMetadata() - .editSpec() - .addToSelector("app", tomcatMetadata.getName()) - .endSpec() - .build(); - }); + @Override + protected Service desired(Tomcat tomcat, Context context) { + final ObjectMeta tomcatMetadata = tomcat.getMetadata(); + return new ServiceBuilder(TomcatReconciler.loadYaml(Service.class, "service.yaml")) + .editMetadata() + .withName(tomcatMetadata.getName()) + .withNamespace(tomcatMetadata.getNamespace()) + .endMetadata() + .editSpec() + .addToSelector("app", tomcatMetadata.getName()) + .endSpec() + .build(); } } diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java index e6fa660e26..ea46e4025c 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java @@ -17,6 +17,7 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_FINALIZER; @@ -42,9 +43,9 @@ public WebPageReconciler(KubernetesClient kubernetesClient) { @Override public List prepareEventSources(EventSourceContext context) { List eventSources = new ArrayList<>(3); - configMapDR.eventSource(context).ifPresent(es -> eventSources.add(es)); - deploymentDR.eventSource(context).ifPresent(es -> eventSources.add(es)); - serviceDR.eventSource(context).ifPresent(es -> eventSources.add(es)); + configMapDR.eventSource(context).ifPresent(eventSources::add); + deploymentDR.eventSource(context).ifPresent(eventSources::add); + serviceDR.eventSource(context).ifPresent(eventSources::add); return eventSources; } @@ -83,72 +84,35 @@ public Optional updateErrorStatus( } private void createDependentResources(KubernetesClient client) { - this.configMapDR = - new KubernetesDependentResource<>( - client, - ConfigMap.class, - (WebPage webPage, Context context) -> { - Map data = new HashMap<>(); - data.put("index.html", webPage.getSpec().getHtml()); - return new ConfigMapBuilder() - .withMetadata( - new ObjectMetaBuilder() - .withName(configMapName(webPage)) - .withNamespace(webPage.getMetadata().getNamespace()) - .build()) - .withData(data) - .build(); - }) { - @Override - protected boolean match(ConfigMap actual, ConfigMap target, Context context) { - return StringUtils.equals( - actual.getData().get("index.html"), target.getData().get("index.html")); - } + this.configMapDR = new ConfigMapDependentResource(); + this.deploymentDR = + new KubernetesDependentResource<>() { @Override - protected ConfigMap update( - ConfigMap actual, ConfigMap target, WebPage primary, Context context) { - var cm = super.update(actual, target, primary, context); - var ns = actual.getMetadata().getNamespace(); - log.info("Restarting pods because HTML has changed in {}", ns); - kubernetesClient - .pods() - .inNamespace(ns) - .withLabel("app", deploymentName(primary)) - .delete(); - return cm; + protected Deployment desired(WebPage webPage, Context context) { + var deploymentName = deploymentName(webPage); + Deployment deployment = loadYaml(Deployment.class, "deployment.yaml"); + deployment.getMetadata().setName(deploymentName); + deployment.getMetadata().setNamespace(webPage.getMetadata().getNamespace()); + deployment.getSpec().getSelector().getMatchLabels().put("app", deploymentName); + + deployment + .getSpec() + .getTemplate() + .getMetadata() + .getLabels() + .put("app", deploymentName); + deployment + .getSpec() + .getTemplate() + .getSpec() + .getVolumes() + .get(0) + .setConfigMap( + new ConfigMapVolumeSourceBuilder().withName(configMapName(webPage)).build()); + return deployment; } - }; - configMapDR.setAssociatedSecondaryResourceIdentifier( - primary -> new ResourceID(configMapName(primary), primary.getMetadata().getNamespace())); - this.deploymentDR = - new KubernetesDependentResource<>( - client, - Deployment.class, - (webPage, context) -> { - var deploymentName = deploymentName(webPage); - Deployment deployment = loadYaml(Deployment.class, "deployment.yaml"); - deployment.getMetadata().setName(deploymentName); - deployment.getMetadata().setNamespace(webPage.getMetadata().getNamespace()); - deployment.getSpec().getSelector().getMatchLabels().put("app", deploymentName); - - deployment - .getSpec() - .getTemplate() - .getMetadata() - .getLabels() - .put("app", deploymentName); - deployment - .getSpec() - .getTemplate() - .getSpec() - .getVolumes() - .get(0) - .setConfigMap( - new ConfigMapVolumeSourceBuilder().withName(configMapName(webPage)).build()); - return deployment; - }) { @Override protected boolean match(Deployment actual, Deployment target, Context context) { // todo comparator @@ -157,18 +121,18 @@ protected boolean match(Deployment actual, Deployment target, Context context) { }; this.serviceDR = - new KubernetesDependentResource<>( - client, - Service.class, - (webPage, context) -> { - Service service = loadYaml(Service.class, "service.yaml"); - service.getMetadata().setName(serviceName(webPage)); - service.getMetadata().setNamespace(webPage.getMetadata().getNamespace()); - Map labels = new HashMap<>(); - labels.put("app", deploymentName(webPage)); - service.getSpec().setSelector(labels); - return service; - }) { + new KubernetesDependentResource<>() { + + @Override + protected Service desired(WebPage webPage, Context context) { + Service service = loadYaml(Service.class, "service.yaml"); + service.getMetadata().setName(serviceName(webPage)); + service.getMetadata().setNamespace(webPage.getMetadata().getNamespace()); + Map labels = new HashMap<>(); + labels.put("app", deploymentName(webPage)); + service.getSpec().setSelector(labels); + return service; + } protected boolean match(Service actual, Service target, Context context) { // todo comparator @@ -196,4 +160,48 @@ private T loadYaml(Class clazz, String yaml) { throw new IllegalStateException("Cannot find yaml on classpath: " + yaml); } } + + private class ConfigMapDependentResource extends KubernetesDependentResource + implements + AssociatedSecondaryResourceIdentifier { + + @Override + protected ConfigMap desired(WebPage webPage, Context context) { + Map data = new HashMap<>(); + data.put("index.html", webPage.getSpec().getHtml()); + return new ConfigMapBuilder() + .withMetadata( + new ObjectMetaBuilder() + .withName(WebPageReconciler.configMapName(webPage)) + .withNamespace(webPage.getMetadata().getNamespace()) + .build()) + .withData(data) + .build(); + } + + @Override + protected boolean match(ConfigMap actual, ConfigMap target, Context context) { + return StringUtils.equals( + actual.getData().get("index.html"), target.getData().get("index.html")); + } + + @Override + protected ConfigMap update( + ConfigMap actual, ConfigMap target, WebPage primary, Context context) { + var cm = super.update(actual, target, primary, context); + var ns = actual.getMetadata().getNamespace(); + log.info("Restarting pods because HTML has changed in {}", ns); + kubernetesClient + .pods() + .inNamespace(ns) + .withLabel("app", deploymentName(primary)) + .delete(); + return cm; + } + + @Override + public ResourceID associatedSecondaryID(WebPage primary) { + return new ResourceID(configMapName(primary), primary.getMetadata().getNamespace()); + } + } } From 9e0a85591149a93a41d9bc03e0b24d1646d7fa5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 16 Feb 2022 08:42:31 +0100 Subject: [PATCH 10/10] Configs final (#937) --- .../api/config/ControllerConfiguration.java | 4 +- .../ControllerConfigurationOverrider.java | 43 +++++- .../DefaultControllerConfiguration.java | 8 +- .../operator/api/config/Utils.java | 11 ++ .../api/config/dependent/Dependent.java | 10 -- .../DependentResourceConfiguration.java | 11 -- .../dependent/DependentResourceSpec.java | 29 ++++ ...ernetesDependentResourceConfiguration.java | 61 --------- .../reconciler/ControllerConfiguration.java | 2 +- .../EventSourceContextInjector.java | 5 - .../dependent/AbstractDependentResource.java | 3 +- .../api/reconciler/dependent/Dependent.java | 6 + .../dependent/DependentResource.java | 9 +- .../operator/processing/Controller.java | 1 - .../dependent/DependentResourceManager.java | 67 +++++----- .../kubernetes}/KubernetesDependent.java | 6 +- .../KubernetesDependentResource.java | 54 +++++--- .../KubernetesDependentResourceConfig.java | 62 +++++++++ .../operator/api/config/UtilsTest.java | 30 +++++ .../operator/junit/OperatorExtension.java | 33 ++++- ...=> AnnotationControllerConfiguration.java} | 126 ++++++++---------- .../runtime/DefaultConfigurationService.java | 2 +- .../StandaloneDependentTestReconciler.java | 3 +- .../operator/sample/MySQLSchemaOperator.java | 15 ++- .../sample/MySQLSchemaReconciler.java | 24 +--- .../operator/sample/ResourcePollerConfig.java | 21 +++ .../sample/SchemaDependentResource.java | 14 +- .../sample/SecretDependentResource.java | 2 +- .../sample/MySQLSchemaOperatorE2E.java | 115 ++++++++-------- .../sample/DeploymentDependentResource.java | 5 +- .../sample/ServiceDependentResource.java | 3 +- .../operator/sample/TomcatReconciler.java | 7 +- .../operator/sample/WebPageReconciler.java | 13 +- 33 files changed, 478 insertions(+), 327 deletions(-) delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/Dependent.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceConfiguration.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceSpec.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceContextInjector.java create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Dependent.java rename operator-framework-core/src/main/java/io/javaoperatorsdk/operator/{api/config/dependent => processing/dependent/kubernetes}/KubernetesDependent.java (84%) rename operator-framework-core/src/main/java/io/javaoperatorsdk/operator/{api/reconciler/dependent => processing/dependent/kubernetes}/KubernetesDependentResource.java (73%) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java create mode 100644 operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/UtilsTest.java rename operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/{AnnotationConfiguration.java => AnnotationControllerConfiguration.java} (52%) create mode 100644 sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/ResourcePollerConfig.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java index c077a7876d..40b32043af 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfiguration.java @@ -7,7 +7,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.ReconcilerUtils; -import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; +import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec; import io.javaoperatorsdk.operator.api.reconciler.Constants; import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter; import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilters; @@ -50,7 +50,7 @@ default ResourceEventFilter getEventFilter() { return ResourceEventFilters.passthrough(); } - default List getDependentResources() { + default List getDependentResources() { return Collections.emptyList(); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java index b21ca22b46..141b58ded0 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ControllerConfigurationOverrider.java @@ -3,9 +3,12 @@ import java.time.Duration; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec; +import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter; public class ControllerConfigurationOverrider { @@ -18,6 +21,7 @@ public class ControllerConfigurationOverrider { private ResourceEventFilter customResourcePredicate; private final ControllerConfiguration original; private Duration reconciliationMaxInterval; + private List dependentResourceSpecs; private ControllerConfigurationOverrider(ControllerConfiguration original) { finalizer = original.getFinalizer(); @@ -27,8 +31,8 @@ private ControllerConfigurationOverrider(ControllerConfiguration original) { labelSelector = original.getLabelSelector(); customResourcePredicate = original.getEventFilter(); reconciliationMaxInterval = original.reconciliationMaxInterval().orElse(null); + dependentResourceSpecs = original.getDependentResources(); this.original = original; - } public ControllerConfigurationOverrider withFinalizer(String finalizer) { @@ -84,6 +88,41 @@ public ControllerConfigurationOverrider withReconciliationMaxInterval( return this; } + /** + * If a {@link DependentResourceSpec} already exists with the same dependentResourceClass it will + * be replaced. Otherwise, an exception is thrown; + * + * @param dependentResourceSpec to add or replace + */ + public void replaceDependentResourceConfig(DependentResourceSpec dependentResourceSpec) { + var currentConfig = + findConfigForDependentResourceClass(dependentResourceSpec.getDependentResourceClass()); + if (currentConfig.isEmpty()) { + throw new IllegalStateException("Cannot find DependentResource config for class: " + + dependentResourceSpec.getDependentResourceClass()); + } + dependentResourceSpecs.remove(currentConfig.get()); + dependentResourceSpecs.add(dependentResourceSpec); + } + + public void addNewDependentResourceConfig(DependentResourceSpec dependentResourceSpec) { + var currentConfig = + findConfigForDependentResourceClass(dependentResourceSpec.getDependentResourceClass()); + if (currentConfig.isPresent()) { + throw new IllegalStateException( + "Config already present for class: " + + dependentResourceSpec.getDependentResourceClass()); + } + dependentResourceSpecs.add(dependentResourceSpec); + } + + private Optional findConfigForDependentResourceClass( + Class dependentResourceClass) { + return dependentResourceSpecs.stream() + .filter(dc -> dc.getDependentResourceClass().equals(dependentResourceClass)) + .findFirst(); + } + public ControllerConfiguration build() { return new DefaultControllerConfiguration<>( original.getAssociatedReconcilerClassName(), @@ -98,7 +137,7 @@ public ControllerConfiguration build() { original.getResourceClass(), reconciliationMaxInterval, original.getConfigurationService(), - original.getDependentResources()); + dependentResourceSpecs); } public static ControllerConfigurationOverrider override( diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultControllerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultControllerConfiguration.java index 188311cfdb..8ce59dd01e 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultControllerConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/DefaultControllerConfiguration.java @@ -7,7 +7,7 @@ import java.util.Set; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; +import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec; import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter; public class DefaultControllerConfiguration @@ -21,7 +21,7 @@ public class DefaultControllerConfiguration private final boolean generationAware; private final RetryConfiguration retryConfiguration; private final ResourceEventFilter resourceEventFilter; - private final List dependents; + private final List dependents; private final Duration reconciliationMaxInterval; // NOSONAR constructor is meant to provide all information @@ -38,7 +38,7 @@ public DefaultControllerConfiguration( Class resourceClass, Duration reconciliationMaxInterval, ConfigurationService service, - List dependents) { + List dependents) { super(labelSelector, resourceClass, namespaces); this.associatedControllerClassName = associatedControllerClassName; this.name = name; @@ -102,7 +102,7 @@ public ResourceEventFilter getEventFilter() { } @Override - public List getDependentResources() { + public List getDependentResources() { return dependents; } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Utils.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Utils.java index 3944cd3ecc..8d9990ee9c 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Utils.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/Utils.java @@ -2,10 +2,12 @@ import java.io.IOException; import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.text.SimpleDateFormat; import java.time.Instant; import java.util.Date; import java.util.Properties; +import java.util.function.Function; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,8 +71,17 @@ public static boolean debugThreadPool() { return Boolean.getBoolean(System.getProperty(DEBUG_THREAD_POOL_ENV_KEY, "false")); } + public static Class getFirstTypeArgumentFromExtendedClass(Class clazz) { + Type type = clazz.getGenericSuperclass(); + return (Class) ((ParameterizedType) type).getActualTypeArguments()[0]; + } + public static Class getFirstTypeArgumentFromInterface(Class clazz) { ParameterizedType type = (ParameterizedType) clazz.getGenericInterfaces()[0]; return (Class) type.getActualTypeArguments()[0]; } + + public static T valueOrDefault(C annotation, Function mapper, T defaultValue) { + return annotation == null ? defaultValue : mapper.apply(annotation); + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/Dependent.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/Dependent.java deleted file mode 100644 index 017f4363a6..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/Dependent.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.javaoperatorsdk.operator.api.config.dependent; - -import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; - -public @interface Dependent { - - Class resourceType(); - - Class type(); -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceConfiguration.java deleted file mode 100644 index 04c80d6413..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceConfiguration.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.javaoperatorsdk.operator.api.config.dependent; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; - -public interface DependentResourceConfiguration { - - Class>> getDependentResourceClass(); - - Class getResourceClass(); -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceSpec.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceSpec.java new file mode 100644 index 0000000000..aea90b5e36 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/DependentResourceSpec.java @@ -0,0 +1,29 @@ +package io.javaoperatorsdk.operator.api.config.dependent; + +import java.util.Optional; + +import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; + +public class DependentResourceSpec, C> { + + private final Class dependentResourceClass; + + private final C dependentResourceConfig; + + public DependentResourceSpec(Class dependentResourceClass) { + this(dependentResourceClass, null); + } + + public DependentResourceSpec(Class dependentResourceClass, C dependentResourceConfig) { + this.dependentResourceClass = dependentResourceClass; + this.dependentResourceConfig = dependentResourceConfig; + } + + public Class getDependentResourceClass() { + return dependentResourceClass; + } + + public Optional getDependentResourceConfiguration() { + return Optional.ofNullable(dependentResourceConfig); + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java deleted file mode 100644 index f38d0b0c93..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependentResourceConfiguration.java +++ /dev/null @@ -1,61 +0,0 @@ -package io.javaoperatorsdk.operator.api.config.dependent; - -import java.util.Set; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.config.ConfigurationService; -import io.javaoperatorsdk.operator.api.config.DefaultResourceConfiguration; -import io.javaoperatorsdk.operator.api.config.ResourceConfiguration; -import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; -import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; - -public interface KubernetesDependentResourceConfiguration - extends DependentResourceConfiguration, ResourceConfiguration { - - boolean isOwned(); - - @Override - default Class getResourceClass() { - return ResourceConfiguration.super.getResourceClass(); - } - - class DefaultKubernetesDependentResourceConfiguration - extends DefaultResourceConfiguration - implements KubernetesDependentResourceConfiguration { - - - private final Class>> dependentResourceClass; - private final boolean owned; - - protected DefaultKubernetesDependentResourceConfiguration( - ConfigurationService configurationService, - String labelSelector, Class resourceClass, - Set namespaces, boolean owned, - Class>> dependentResourceClass) { - super(labelSelector, resourceClass, namespaces); - setConfigurationService(configurationService); - this.owned = owned; - this.dependentResourceClass = dependentResourceClass; - } - - @Override - public boolean isOwned() { - return owned; - } - - @Override - public Class>> getDependentResourceClass() { - return dependentResourceClass; - } - } - - @SuppressWarnings({"rawtypes", "unchecked"}) - static KubernetesDependentResourceConfiguration from( - InformerConfiguration cfg, boolean owned, - Class dependentResourceClass) { - return new DefaultKubernetesDependentResourceConfiguration<>(cfg.getConfigurationService(), - cfg.getLabelSelector(), cfg.getResourceClass(), - cfg.getNamespaces(), owned, - (Class>>) dependentResourceClass); - } -} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java index 6d964e26ad..7d4c1fd0e8 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ControllerConfiguration.java @@ -5,7 +5,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import io.javaoperatorsdk.operator.api.config.dependent.Dependent; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter; @Retention(RetentionPolicy.RUNTIME) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceContextInjector.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceContextInjector.java deleted file mode 100644 index af57fe1b32..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceContextInjector.java +++ /dev/null @@ -1,5 +0,0 @@ -package io.javaoperatorsdk.operator.api.reconciler; - -public interface EventSourceContextInjector { - void injectInto(EventSourceContext context); -} 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 74df7e7960..beac9ef4bb 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 @@ -1,10 +1,9 @@ package io.javaoperatorsdk.operator.api.reconciler.dependent; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; -public abstract class AbstractDependentResource> +public abstract class AbstractDependentResource implements DependentResource { @Override diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Dependent.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Dependent.java new file mode 100644 index 0000000000..21f0b4f55b --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/Dependent.java @@ -0,0 +1,6 @@ +package io.javaoperatorsdk.operator.api.reconciler.dependent; + +public @interface Dependent { + + Class type(); +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java index 01cdb66b60..5208480166 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/DependentResource.java @@ -3,21 +3,14 @@ import java.util.Optional; import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.api.config.Utils; -import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.processing.event.source.EventSource; -public interface DependentResource> { +public interface DependentResource { Optional eventSource(EventSourceContext

context); - @SuppressWarnings("unchecked") - default Class resourceType() { - return (Class) Utils.getFirstTypeArgumentFromInterface(getClass()); - } - void reconcile(P primary, Context context); void delete(P primary, Context context); 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 f3ad2dd8ec..89aabe0d9b 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 @@ -217,7 +217,6 @@ public void start() throws OperatorException { eventSourceManager.getControllerResourceEventSource().getResourceCache(), configurationService(), kubernetesClient); - dependents.injectInto(context); prepareEventSources(context).forEach(eventSourceManager::registerEventSource); eventSourceManager.start(); 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 index 3e1d1c9f0a..6f3a98b4dd 100644 --- 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 @@ -5,15 +5,17 @@ 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.DependentResourceConfiguration; +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.EventSourceContextInjector; import io.javaoperatorsdk.operator.api.reconciler.EventSourceInitializer; import io.javaoperatorsdk.operator.api.reconciler.Ignore; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; @@ -25,8 +27,11 @@ @SuppressWarnings({"rawtypes", "unchecked"}) @Ignore -public class DependentResourceManager

implements EventSourceInitializer

, - EventSourceContextInjector, Reconciler

{ +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; @@ -38,29 +43,23 @@ public DependentResourceManager(Controller

controller) { @Override public List prepareEventSources(EventSourceContext

context) { - final var dependentConfigurations = controllerConfiguration.getDependentResources(); - final var sources = new ArrayList(dependentConfigurations.size()); - - dependents = dependentConfigurations.stream() - .map(drc -> { - final var dependentResource = from(drc, context.getClient()); - dependentResource.eventSource(context) - .ifPresent(es -> sources.add((EventSource) es)); - return dependentResource; - }) - .collect(Collectors.toList()); - + final var dependentResources = controllerConfiguration.getDependentResources(); + final var sources = new ArrayList(dependentResources.size()); + dependents = + dependentResources.stream() + .map( + drc -> { + final var dependentResource = + from(drc, context.getClient()); + dependentResource + .eventSource(context) + .ifPresent(es -> sources.add((EventSource) es)); + return dependentResource; + }) + .collect(Collectors.toList()); return sources; } - @Override - public void injectInto(EventSourceContext context) { - if (reconciler instanceof EventSourceContextInjector) { - EventSourceContextInjector injector = (EventSourceContextInjector) reconciler; - injector.injectInto(context); - } - } - @Override public UpdateControl

reconcile(P resource, Context context) { initContextIfNeeded(resource, context); @@ -75,7 +74,6 @@ public DeleteControl cleanup(P resource, Context context) { return Reconciler.super.cleanup(resource, context); } - private void initContextIfNeeded(P resource, Context context) { if (reconciler instanceof ContextInitializer) { final var initializer = (ContextInitializer

) reconciler; @@ -83,21 +81,20 @@ private void initContextIfNeeded(P resource, Context context) { } } - private DependentResource from(DependentResourceConfiguration config, KubernetesClient client) { + private DependentResource from(DependentResourceSpec dependentResourceSpec, + KubernetesClient client) { try { - final var dependentResource = - (DependentResource) config.getDependentResourceClass().getConstructor().newInstance(); + DependentResource dependentResource = + (DependentResource) dependentResourceSpec.getDependentResourceClass() + .getConstructor().newInstance(); if (dependentResource instanceof KubernetesClientAware) { ((KubernetesClientAware) dependentResource).setKubernetesClient(client); } - - dependentResource.configureWith(config); - + dependentResourceSpec.getDependentResourceConfiguration() + .ifPresent(dependentResource::configureWith); return dependentResource; - } catch (InstantiationException - | IllegalAccessException - | InvocationTargetException - | NoSuchMethodException e) { + } catch (InstantiationException | NoSuchMethodException | IllegalAccessException + | InvocationTargetException e) { throw new IllegalStateException(e); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependent.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependent.java similarity index 84% rename from operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependent.java rename to operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependent.java index 64fc656f65..c0922f569f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/dependent/KubernetesDependent.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependent.java @@ -1,4 +1,4 @@ -package io.javaoperatorsdk.operator.api.config.dependent; +package io.javaoperatorsdk.operator.processing.dependent.kubernetes; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -11,9 +11,9 @@ @Target({ElementType.TYPE}) public @interface KubernetesDependent { - boolean OWNED_DEFAULT = true; + boolean ADD_OWNER_REFERENCE_DEFAULT = true; - boolean owned() default OWNED_DEFAULT; + boolean addOwnerReference() default ADD_OWNER_REFERENCE_DEFAULT; /** * Specified which namespaces this Controller monitors for custom resources events. If no diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java similarity index 73% rename from operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java rename to operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index ac35cc2441..a805c12b11 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -1,4 +1,4 @@ -package io.javaoperatorsdk.operator.api.reconciler.dependent; +package io.javaoperatorsdk.operator.processing.dependent.kubernetes; import java.util.Optional; import java.util.Set; @@ -10,11 +10,12 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.ReconcilerUtils; import io.javaoperatorsdk.operator.api.config.ConfigurationService; -import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependent; -import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependentResourceConfiguration; +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; +import io.javaoperatorsdk.operator.api.reconciler.dependent.AbstractDependentResource; +import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesClientAware; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; import io.javaoperatorsdk.operator.processing.event.source.EventSource; @@ -23,23 +24,24 @@ import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; public abstract class KubernetesDependentResource - extends AbstractDependentResource> + extends AbstractDependentResource implements KubernetesClientAware { private static final Logger log = LoggerFactory.getLogger(KubernetesDependentResource.class); protected KubernetesClient client; private InformerEventSource informerEventSource; - private KubernetesDependentResourceConfiguration configuration; + private boolean addOwnerReference; - public void configureWith(KubernetesDependentResourceConfiguration config) { - configureWith(config.getConfigurationService(), config.getLabelSelector(), - config.getNamespaces(), config.isOwned()); + @Override + public void configureWith(KubernetesDependentResourceConfig config) { + configureWith(config.getConfigurationService(), config.labelSelector(), + Set.of(config.namespaces()), config.addOwnerReference()); } @SuppressWarnings("unchecked") private void configureWith(ConfigurationService service, String labelSelector, - Set namespaces, boolean owned) { + Set namespaces, boolean addOwnerReference) { final var primaryResourcesRetriever = (this instanceof PrimaryResourcesRetriever) ? (PrimaryResourcesRetriever) this : Mappers.fromOwnerReference(); @@ -54,12 +56,24 @@ private void configureWith(ConfigurationService service, String labelSelector, .withPrimaryResourcesRetriever(primaryResourcesRetriever) .withAssociatedSecondaryResourceIdentifier(secondaryResourceIdentifier) .build(); - configuration = KubernetesDependentResourceConfiguration.from(ic, owned, getClass()); + this.addOwnerReference = addOwnerReference; informerEventSource = new InformerEventSource<>(ic, client); } + /** + * Use to share informers between event more resources. + * + * @param informerEventSource informer to use + * @param addOwnerReference to the created resource + */ + public void configureWith(InformerEventSource informerEventSource, + boolean addOwnerReference) { + this.informerEventSource = informerEventSource; + this.addOwnerReference = addOwnerReference; + } + protected void beforeCreateOrUpdate(R desired, P primary) { - if (configuration.isOwned()) { + if (addOwnerReference) { desired.addOwnerReference(primary); } } @@ -95,7 +109,7 @@ protected R update(R actual, R target, P primary, Context context) { public Optional eventSource(EventSourceContext

context) { if (informerEventSource == null) { configureWith(context.getConfigurationService(), null, null, - KubernetesDependent.OWNED_DEFAULT); + KubernetesDependent.ADD_OWNER_REFERENCE_DEFAULT); log.warn("Using default configuration for " + resourceType().getSimpleName() + " KubernetesDependentResource, call configureWith to provide configuration"); } @@ -110,9 +124,15 @@ public KubernetesDependentResource setInformerEventSource( @Override public void delete(P primary, Context context) { - // todo: do we need explicit delete? If yes, add it to configuration - var resource = getResource(primary); - resource.ifPresent(r -> client.resource(r).delete()); + if (addOwnerReference) { + var resource = getResource(primary); + resource.ifPresent(r -> client.resource(r).delete()); + } + } + + @SuppressWarnings("unchecked") + protected Class resourceType() { + return (Class) Utils.getFirstTypeArgumentFromExtendedClass(getClass()); } @Override @@ -121,7 +141,7 @@ public Optional getResource(P primaryResource) { } @Override - public void setKubernetesClient(KubernetesClient client) { - this.client = client; + public void setKubernetesClient(KubernetesClient kubernetesClient) { + this.client = kubernetesClient; } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java new file mode 100644 index 0000000000..4464f3fd7d --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfig.java @@ -0,0 +1,62 @@ +package io.javaoperatorsdk.operator.processing.dependent.kubernetes; + +import io.javaoperatorsdk.operator.api.config.ConfigurationService; + +import static io.javaoperatorsdk.operator.api.reconciler.Constants.EMPTY_STRING; +import static io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent.ADD_OWNER_REFERENCE_DEFAULT; + +public class KubernetesDependentResourceConfig { + + private boolean addOwnerReference = ADD_OWNER_REFERENCE_DEFAULT; + private String[] namespaces = new String[0]; + private String labelSelector = EMPTY_STRING; + private ConfigurationService configurationService; + + public KubernetesDependentResourceConfig() {} + + public KubernetesDependentResourceConfig(boolean addOwnerReference, String[] namespaces, + String labelSelector, ConfigurationService configurationService) { + this.addOwnerReference = addOwnerReference; + this.namespaces = namespaces; + this.labelSelector = labelSelector; + this.configurationService = configurationService; + } + + public KubernetesDependentResourceConfig setAddOwnerReference( + boolean addOwnerReference) { + this.addOwnerReference = addOwnerReference; + return this; + } + + public KubernetesDependentResourceConfig setNamespaces(String[] namespaces) { + this.namespaces = namespaces; + return this; + } + + public KubernetesDependentResourceConfig setLabelSelector(String labelSelector) { + this.labelSelector = labelSelector; + return this; + } + + public KubernetesDependentResourceConfig setConfigurationService( + ConfigurationService configurationService) { + this.configurationService = configurationService; + return this; + } + + public boolean addOwnerReference() { + return addOwnerReference; + } + + public String[] namespaces() { + return namespaces; + } + + public String labelSelector() { + return labelSelector; + } + + public ConfigurationService getConfigurationService() { + return configurationService; + } +} 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 new file mode 100644 index 0000000000..88dd8db469 --- /dev/null +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/UtilsTest.java @@ -0,0 +1,30 @@ +package io.javaoperatorsdk.operator.api.config; + +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.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.*; + +class UtilsTest { + + @Test + void getsFirstTypeArgumentFromExtendedClass() { + Class res = + Utils.getFirstTypeArgumentFromExtendedClass(TestKubernetesDependentResource.class); + assertThat(res).isEqualTo(Deployment.class); + } + + public static class TestKubernetesDependentResource + extends KubernetesDependentResource { + + @Override + protected Deployment desired(TestCustomResource primary, Context context) { + return null; + } + } +} diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/OperatorExtension.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/OperatorExtension.java index 76d848c896..c445acf67c 100644 --- a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/OperatorExtension.java +++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/OperatorExtension.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -15,6 +16,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.Operator; import io.javaoperatorsdk.operator.api.config.ConfigurationService; +import io.javaoperatorsdk.operator.api.config.ControllerConfigurationOverrider; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.processing.Controller; import io.javaoperatorsdk.operator.processing.retry.Retry; @@ -37,7 +39,11 @@ private OperatorExtension( boolean preserveNamespaceOnError, boolean waitForNamespaceDeletion, boolean oneNamespacePerClass) { - super(configurationService, infrastructure, infrastructureTimeout, oneNamespacePerClass, + super( + configurationService, + infrastructure, + infrastructureTimeout, + oneNamespacePerClass, preserveNamespaceOnError, waitForNamespaceDeletion); this.reconcilers = reconcilers; @@ -86,6 +92,9 @@ protected void before(ExtensionContext context) { if (ref.retry != null) { oconfig.withRetry(ref.retry); } + if (ref.controllerConfigurationOverrider != null) { + ref.controllerConfigurationOverrider.accept(oconfig); + } final var kubernetesClient = getKubernetesClient(); try (InputStream is = getClass().getResourceAsStream(path)) { @@ -127,6 +136,19 @@ protected Builder() { this.reconcilers = new ArrayList<>(); } + public Builder withReconciler( + Reconciler value, Consumer configurationOverrider) { + return withReconciler(value, null, configurationOverrider); + } + + public Builder withReconciler( + Reconciler value, + Retry retry, + Consumer configurationOverrider) { + reconcilers.add(new ReconcilerSpec(value, retry, configurationOverrider)); + return this; + } + @SuppressWarnings("rawtypes") public Builder withReconciler(Reconciler value) { reconcilers.add(new ReconcilerSpec(value, null)); @@ -165,10 +187,19 @@ public OperatorExtension build() { private static class ReconcilerSpec { final Reconciler reconciler; final Retry retry; + final Consumer controllerConfigurationOverrider; public ReconcilerSpec(Reconciler reconciler, Retry retry) { + this(reconciler, retry, null); + } + + public ReconcilerSpec( + Reconciler reconciler, + Retry retry, + Consumer controllerConfigurationOverrider) { this.reconciler = reconciler; this.retry = retry; + this.controllerConfigurationOverrider = controllerConfigurationOverrider; } } } diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationConfiguration.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationControllerConfiguration.java similarity index 52% rename from operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationConfiguration.java rename to operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationControllerConfiguration.java index ab38d537d7..dd1e005fc1 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationConfiguration.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/AnnotationControllerConfiguration.java @@ -1,37 +1,34 @@ package io.javaoperatorsdk.operator.config.runtime; import java.time.Duration; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.Set; +import java.util.*; import java.util.function.Function; +import java.util.stream.Collectors; import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.ReconcilerUtils; import io.javaoperatorsdk.operator.api.config.ConfigurationService; -import io.javaoperatorsdk.operator.api.config.dependent.Dependent; -import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; -import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependent; -import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependentResourceConfiguration; -import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; +import io.javaoperatorsdk.operator.api.config.Utils; +import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec; import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfig; import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilter; import io.javaoperatorsdk.operator.processing.event.source.controller.ResourceEventFilters; @SuppressWarnings("rawtypes") -public class AnnotationConfiguration +public class AnnotationControllerConfiguration implements io.javaoperatorsdk.operator.api.config.ControllerConfiguration { private final Reconciler reconciler; private final ControllerConfiguration annotation; private ConfigurationService service; - private List dependentConfigurations; - public AnnotationConfiguration(Reconciler reconciler) { + public AnnotationControllerConfiguration(Reconciler reconciler) { this.reconciler = reconciler; this.annotation = reconciler.getClass().getAnnotation(ControllerConfiguration.class); } @@ -50,16 +47,17 @@ public String getFinalizer() { if (ReconcilerUtils.isFinalizerValid(finalizer)) { return finalizer; } else { - throw new IllegalArgumentException(finalizer - + " is not a valid finalizer. See https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#finalizers for details"); + throw new IllegalArgumentException( + finalizer + + " is not a valid finalizer. See https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/#finalizers for details"); } } } @Override public boolean isGenerationAware() { - return valueOrDefault(annotation, ControllerConfiguration::generationAwareEventProcessing, - true); + return valueOrDefault( + annotation, ControllerConfiguration::generationAwareEventProcessing, true); } @Override @@ -99,8 +97,7 @@ public ResourceEventFilter getEventFilter() { Class>[] filterTypes = (Class>[]) valueOrDefault(annotation, - ControllerConfiguration::eventFilters, - new Object[] {}); + ControllerConfiguration::eventFilters, new Object[] {}); if (filterTypes.length > 0) { for (var filterType : filterTypes) { try { @@ -116,9 +113,7 @@ public ResourceEventFilter getEventFilter() { } } } - return answer != null - ? answer - : ResourceEventFilters.passthrough(); + return answer != null ? answer : ResourceEventFilters.passthrough(); } @Override @@ -127,8 +122,10 @@ public Optional reconciliationMaxInterval() { if (annotation.reconciliationMaxInterval().interval() <= 0) { return Optional.empty(); } - return Optional.of(Duration.of(annotation.reconciliationMaxInterval().interval(), - annotation.reconciliationMaxInterval().timeUnit().toChronoUnit())); + return Optional.of( + Duration.of( + annotation.reconciliationMaxInterval().interval(), + annotation.reconciliationMaxInterval().timeUnit().toChronoUnit())); } else { return io.javaoperatorsdk.operator.api.config.ControllerConfiguration.super.reconciliationMaxInterval(); } @@ -146,56 +143,41 @@ public static T valueOrDefault( } @Override - public List getDependentResources() { - if (dependentConfigurations == null) { - final var dependents = valueOrDefault(annotation, ControllerConfiguration::dependents, - new Dependent[] {}); - if (dependents.length > 0) { - dependentConfigurations = new ArrayList<>(dependents.length); - for (Dependent dependent : dependents) { - final Class dependentType = dependent.type(); - final var resourceType = dependent.resourceType(); - - if (HasMetadata.class.isAssignableFrom(resourceType)) { - final var kubeDependent = dependentType.getAnnotation(KubernetesDependent.class); - final var namespaces = - valueOrDefault(kubeDependent, KubernetesDependent::namespaces, - this.getNamespaces().toArray(new String[0])); - final var labelSelector = - valueOrDefault(kubeDependent, KubernetesDependent::labelSelector, null); - final var owned = valueOrDefault(kubeDependent, KubernetesDependent::owned, - KubernetesDependent.OWNED_DEFAULT); - - final var configuration = InformerConfiguration.from(service, resourceType) - .withLabelSelector(labelSelector) - .withNamespaces(namespaces) - .build(); - - dependentConfigurations.add( - KubernetesDependentResourceConfiguration.from(configuration, owned, dependentType)); - } else { - dependentConfigurations.add(new DependentResourceConfiguration() { - @Override - public Class getDependentResourceClass() { - return dependentType; - } - - @Override - public Class getResourceClass() { - return resourceType; - } - }); - } - } + public List getDependentResources() { + final var dependents = + valueOrDefault(annotation, ControllerConfiguration::dependents, new Dependent[] {}); + if (dependents.length == 0) { + return Collections.emptyList(); + } + + List resourceSpecs = new ArrayList<>(dependents.length); + for (Dependent dependent : dependents) { + + final Class dependentType = dependent.type(); + if (KubernetesDependentResource.class.isAssignableFrom(dependentType)) { + final var kubeDependent = dependentType.getAnnotation(KubernetesDependent.class); + final var namespaces = + Utils.valueOrDefault( + kubeDependent, + KubernetesDependent::namespaces, + this.getNamespaces().toArray(new String[0])); + final var labelSelector = + Utils.valueOrDefault(kubeDependent, KubernetesDependent::labelSelector, null); + final var addOwnerReference = + Utils.valueOrDefault( + kubeDependent, + KubernetesDependent::addOwnerReference, + KubernetesDependent.ADD_OWNER_REFERENCE_DEFAULT); + KubernetesDependentResourceConfig config = + new KubernetesDependentResourceConfig( + addOwnerReference, namespaces, labelSelector, getConfigurationService()); + resourceSpecs.add(new DependentResourceSpec(dependentType, config)); } else { - dependentConfigurations = Collections.emptyList(); + resourceSpecs.add(new DependentResourceSpec(dependentType)); } } - return dependentConfigurations; - } - - private static T valueOrDefault(C annotation, Function mapper, T defaultValue) { - return annotation == null ? defaultValue : mapper.apply(annotation); + return Arrays.stream(dependents) + .map(d -> new DependentResourceSpec(d.type())) + .collect(Collectors.toList()); } } - diff --git a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/DefaultConfigurationService.java b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/DefaultConfigurationService.java index 44fc674028..21af48cfd1 100644 --- a/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/DefaultConfigurationService.java +++ b/operator-framework/src/main/java/io/javaoperatorsdk/operator/config/runtime/DefaultConfigurationService.java @@ -30,7 +30,7 @@ ControllerConfiguration getConfigurationFor( if (config == null) { if (createIfNeeded) { // create the configuration on demand and register it - config = new AnnotationConfiguration<>(reconciler); + config = new AnnotationControllerConfiguration<>(reconciler); register(config); getLogger().info( "Created configuration for reconciler {} with name {}", 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 44be1721b3..b168d8fb47 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 @@ -9,8 +9,8 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.utils.Serialization; import io.javaoperatorsdk.operator.api.reconciler.*; -import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; import io.javaoperatorsdk.operator.junit.KubernetesClientAware; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.source.EventSource; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_FINALIZER; @@ -80,5 +80,6 @@ protected boolean match(Deployment actual, Deployment target, Context context) { .equals( target.getSpec().getTemplate().getSpec().getContainers().get(0).getImage()); } + } } diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperator.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperator.java index d9012637cf..4fddf8cadc 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperator.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperator.java @@ -15,6 +15,9 @@ import io.fabric8.kubernetes.client.KubernetesClient; import io.javaoperatorsdk.operator.Operator; import io.javaoperatorsdk.operator.api.config.ConfigurationServiceOverrider; +import io.javaoperatorsdk.operator.api.config.ControllerConfigurationOverrider; +import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec; +import io.javaoperatorsdk.operator.config.runtime.AnnotationControllerConfiguration; import io.javaoperatorsdk.operator.config.runtime.DefaultConfigurationService; import io.javaoperatorsdk.operator.monitoring.micrometer.MicrometerMetrics; import io.micrometer.core.instrument.logging.LoggingMeterRegistry; @@ -32,7 +35,17 @@ public static void main(String[] args) throws IOException { new ConfigurationServiceOverrider(DefaultConfigurationService.instance()) .withMetrics(new MicrometerMetrics(new LoggingMeterRegistry())) .build()); - operator.register(new MySQLSchemaReconciler(MySQLDbConfig.loadFromEnvironmentVars())); + + MySQLSchemaReconciler schemaReconciler = new MySQLSchemaReconciler(); + ControllerConfigurationOverrider configOverrider = + ControllerConfigurationOverrider + .override(new AnnotationControllerConfiguration(schemaReconciler)); + + configOverrider.replaceDependentResourceConfig( + new DependentResourceSpec(SchemaDependentResource.class, + new ResourcePollerConfig(500, MySQLDbConfig.loadFromEnvironmentVars()))); + + operator.register(schemaReconciler, configOverrider.build()); operator.installShutdownHook(); operator.start(); diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java index 63c37ac3d7..8965ae2a89 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/MySQLSchemaReconciler.java @@ -6,17 +6,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.fabric8.kubernetes.api.model.Secret; -import io.javaoperatorsdk.operator.api.config.dependent.Dependent; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.ContextInitializer; import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.ErrorStatusHandler; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.api.reconciler.EventSourceContextInjector; import io.javaoperatorsdk.operator.api.reconciler.Reconciler; import io.javaoperatorsdk.operator.api.reconciler.RetryInfo; import io.javaoperatorsdk.operator.api.reconciler.UpdateControl; +import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; import io.javaoperatorsdk.operator.sample.schema.Schema; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_FINALIZER; @@ -25,12 +22,12 @@ // todo handle this, should work with finalizer @ControllerConfiguration(finalizerName = NO_FINALIZER, dependents = { - @Dependent(resourceType = Secret.class, type = SecretDependentResource.class), - @Dependent(resourceType = Schema.class, type = SchemaDependentResource.class) + @Dependent(type = SecretDependentResource.class), + @Dependent(type = SchemaDependentResource.class) }) public class MySQLSchemaReconciler implements Reconciler, ErrorStatusHandler, - ContextInitializer, EventSourceContextInjector { + ContextInitializer { static final String SECRET_FORMAT = "%s-secret"; static final String USERNAME_FORMAT = "%s-user"; @@ -38,21 +35,10 @@ public class MySQLSchemaReconciler static final String MYSQL_SECRET_NAME = "mysql.secret.name"; static final String MYSQL_SECRET_USERNAME = "mysql.secret.user.name"; static final String MYSQL_SECRET_PASSWORD = "mysql.secret.user.password"; - static final String MYSQL_DB_CONFIG = "mysql.db.config"; static final String BUILT_SCHEMA = "built schema"; static final Logger log = LoggerFactory.getLogger(MySQLSchemaReconciler.class); - private final MySQLDbConfig mysqlDbConfig; - - public MySQLSchemaReconciler(MySQLDbConfig mysqlDbConfig) { - this.mysqlDbConfig = mysqlDbConfig; - } - - @SuppressWarnings("rawtypes") - @Override - public void injectInto(EventSourceContext context) { - context.put(MYSQL_DB_CONFIG, mysqlDbConfig); - } + public MySQLSchemaReconciler() {} @Override public void initContext(MySQLSchema primary, Context context) { diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/ResourcePollerConfig.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/ResourcePollerConfig.java new file mode 100644 index 0000000000..924c3978d1 --- /dev/null +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/ResourcePollerConfig.java @@ -0,0 +1,21 @@ +package io.javaoperatorsdk.operator.sample; + +public class ResourcePollerConfig { + + private final int pollPeriod; + private final MySQLDbConfig mySQLDbConfig; + + + public ResourcePollerConfig(int pollPeriod, MySQLDbConfig mySQLDbConfig) { + this.pollPeriod = pollPeriod; + this.mySQLDbConfig = mySQLDbConfig; + } + + public int getPollPeriod() { + return pollPeriod; + } + + public MySQLDbConfig getMySQLDbConfig() { + return mySQLDbConfig; + } +} diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java index 1e0de2393a..62ce1356a2 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SchemaDependentResource.java @@ -5,7 +5,6 @@ import java.sql.SQLException; import java.util.Optional; -import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.dependent.AbstractDependentResource; @@ -17,16 +16,21 @@ import static java.lang.String.format; public class SchemaDependentResource extends - AbstractDependentResource> { + AbstractDependentResource { - private static final int POLL_PERIOD = 500; private MySQLDbConfig dbConfig; + private int pollPeriod; + + @Override + public void configureWith(ResourcePollerConfig config) { + this.dbConfig = config.getMySQLDbConfig(); + this.pollPeriod = config.getPollPeriod(); + } @Override public Optional eventSource(EventSourceContext context) { - dbConfig = context.getMandatory(MySQLSchemaReconciler.MYSQL_DB_CONFIG, MySQLDbConfig.class); return Optional.of(new PerResourcePollingEventSource<>( - new SchemaPollingResourceSupplier(dbConfig), context.getPrimaryCache(), POLL_PERIOD, + new SchemaPollingResourceSupplier(dbConfig), context.getPrimaryCache(), pollPeriod, Schema.class)); } diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java index 475aa1783e..884cc6d2c9 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/SecretDependentResource.java @@ -5,7 +5,7 @@ import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.SecretBuilder; import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; diff --git a/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java b/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java index 0c1be5efc0..f433671c08 100644 --- a/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java +++ b/sample-operators/mysql-schema/src/test/java/io/javaoperatorsdk/operator/sample/MySQLSchemaOperatorE2E.java @@ -17,6 +17,7 @@ import io.fabric8.kubernetes.client.DefaultKubernetesClient; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.LocalPortForward; +import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec; import io.javaoperatorsdk.operator.config.runtime.DefaultConfigurationService; import io.javaoperatorsdk.operator.junit.AbstractOperatorExtension; import io.javaoperatorsdk.operator.junit.E2EOperatorExtension; @@ -31,25 +32,20 @@ class MySQLSchemaOperatorE2E { - final static Logger log = LoggerFactory.getLogger(MySQLSchemaOperatorE2E.class); + static final Logger log = LoggerFactory.getLogger(MySQLSchemaOperatorE2E.class); - final static KubernetesClient client = new DefaultKubernetesClient(); + static final KubernetesClient client = new DefaultKubernetesClient(); - final static String MY_SQL_NS = "mysql"; + static final String MY_SQL_NS = "mysql"; private static List infrastructure = new ArrayList<>(); + static { - infrastructure - .add(new NamespaceBuilder() - .withNewMetadata() - .withName(MY_SQL_NS) - .endMetadata() - .build()); + infrastructure.add( + new NamespaceBuilder().withNewMetadata().withName(MY_SQL_NS).endMetadata().build()); try { - infrastructure.addAll( - client.load(new FileInputStream("k8s/mysql-deployment.yaml")).get()); - infrastructure.addAll( - client.load(new FileInputStream("k8s/mysql-service.yaml")).get()); + infrastructure.addAll(client.load(new FileInputStream("k8s/mysql-deployment.yaml")).get()); + infrastructure.addAll(client.load(new FileInputStream("k8s/mysql-service.yaml")).get()); } catch (FileNotFoundException e) { e.printStackTrace(); } @@ -63,20 +59,26 @@ boolean isLocal() { } @RegisterExtension - AbstractOperatorExtension operator = isLocal() ? OperatorExtension.builder() - .withConfigurationService(DefaultConfigurationService.instance()) - .withReconciler( - new MySQLSchemaReconciler(new MySQLDbConfig("127.0.0.1", "3306", "root", "password"))) - .withInfrastructure(infrastructure) - .build() - : E2EOperatorExtension.builder() - .withConfigurationService(DefaultConfigurationService.instance()) - .withOperatorDeployment( - client.load(new FileInputStream("k8s/operator.yaml")).get()) - .withInfrastructure(infrastructure) - .build(); - - + AbstractOperatorExtension operator = + isLocal() + ? OperatorExtension.builder() + .withConfigurationService(DefaultConfigurationService.instance()) + .withReconciler( + new MySQLSchemaReconciler(), + c -> { + c.replaceDependentResourceConfig( + new DependentResourceSpec( + SchemaDependentResource.class, + new ResourcePollerConfig( + 700, new MySQLDbConfig("127.0.0.1", "3306", "root", "password")))); + }) + .withInfrastructure(infrastructure) + .build() + : E2EOperatorExtension.builder() + .withConfigurationService(DefaultConfigurationService.instance()) + .withOperatorDeployment(client.load(new FileInputStream("k8s/operator.yaml")).get()) + .withInfrastructure(infrastructure) + .build(); public MySQLSchemaOperatorE2E() throws FileNotFoundException {} @@ -85,28 +87,23 @@ public void test() throws IOException { // Opening a port-forward if running locally LocalPortForward portForward = null; if (isLocal()) { - String podName = client - .pods() - .inNamespace(MY_SQL_NS) - .withLabel("app", "mysql") - .list() - .getItems() - .get(0) - .getMetadata() - .getName(); - - portForward = client - .pods() - .inNamespace(MY_SQL_NS) - .withName(podName) - .portForward(3306, 3306); + String podName = + client + .pods() + .inNamespace(MY_SQL_NS) + .withLabel("app", "mysql") + .list() + .getItems() + .get(0) + .getMetadata() + .getName(); + + portForward = client.pods().inNamespace(MY_SQL_NS).withName(podName).portForward(3306, 3306); } MySQLSchema testSchema = new MySQLSchema(); - testSchema.setMetadata(new ObjectMetaBuilder() - .withName("mydb1") - .withNamespace(operator.getNamespace()) - .build()); + testSchema.setMetadata( + new ObjectMetaBuilder().withName("mydb1").withNamespace(operator.getNamespace()).build()); testSchema.setSpec(new SchemaSpec()); testSchema.getSpec().setEncoding("utf8"); @@ -114,19 +111,25 @@ public void test() throws IOException { client.resource(testSchema).createOrReplace(); log.info("Waiting 2 minutes for expected resources to be created and updated"); - await().atMost(2, MINUTES).ignoreExceptions().untilAsserted(() -> { - MySQLSchema updatedSchema = - client.resources(MySQLSchema.class).inNamespace(operator.getNamespace()) - .withName(testSchema.getMetadata().getName()).get(); - assertThat(updatedSchema.getStatus(), is(notNullValue())); - assertThat(updatedSchema.getStatus().getStatus(), equalTo("CREATED")); - assertThat(updatedSchema.getStatus().getSecretName(), is(notNullValue())); - assertThat(updatedSchema.getStatus().getUserName(), is(notNullValue())); - }); + await() + .atMost(2, MINUTES) + .ignoreExceptions() + .untilAsserted( + () -> { + MySQLSchema updatedSchema = + client + .resources(MySQLSchema.class) + .inNamespace(operator.getNamespace()) + .withName(testSchema.getMetadata().getName()) + .get(); + assertThat(updatedSchema.getStatus(), is(notNullValue())); + assertThat(updatedSchema.getStatus().getStatus(), equalTo("CREATED")); + assertThat(updatedSchema.getStatus().getSecretName(), is(notNullValue())); + assertThat(updatedSchema.getStatus().getUserName(), is(notNullValue())); + }); if (portForward != null) { portForward.close(); } } - } diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java index 620e908fea..a0c22ce9b1 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java @@ -3,9 +3,9 @@ import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; -import io.javaoperatorsdk.operator.api.config.dependent.KubernetesDependent; import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; @KubernetesDependent(labelSelector = "app.kubernetes.io/managed-by=tomcat-operator") public class DeploymentDependentResource extends KubernetesDependentResource { @@ -49,4 +49,5 @@ public boolean match(Deployment fetched, Deployment target, Context context) { return fetched.getSpec().getTemplate().getSpec().getContainers().get(0).getImage() .equals(target.getSpec().getTemplate().getSpec().getContainers().get(0).getImage()); } + } 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 e2fdb3f026..df690f6abd 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 @@ -4,7 +4,7 @@ import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServiceBuilder; import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; public class ServiceDependentResource extends KubernetesDependentResource { @@ -21,4 +21,5 @@ protected Service desired(Tomcat tomcat, Context context) { .endSpec() .build(); } + } diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatReconciler.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatReconciler.java index d2d2a6c96c..c84ff61eb1 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatReconciler.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/TomcatReconciler.java @@ -7,15 +7,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.apps.DeploymentStatus; import io.fabric8.kubernetes.client.utils.Serialization; -import io.javaoperatorsdk.operator.api.config.dependent.Dependent; 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 io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent; import static io.javaoperatorsdk.operator.api.reconciler.Constants.NO_FINALIZER; @@ -26,8 +25,8 @@ @ControllerConfiguration( finalizerName = NO_FINALIZER, dependents = { - @Dependent(resourceType = Deployment.class, type = DeploymentDependentResource.class), - @Dependent(resourceType = Service.class, type = ServiceDependentResource.class) + @Dependent(type = DeploymentDependentResource.class), + @Dependent(type = ServiceDependentResource.class) }) public class TomcatReconciler implements Reconciler { diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java index ea46e4025c..cc9bce6c6d 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/WebPageReconciler.java @@ -15,7 +15,7 @@ import io.fabric8.kubernetes.client.utils.Serialization; import io.javaoperatorsdk.operator.api.reconciler.*; import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.api.reconciler.dependent.KubernetesDependentResource; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.AssociatedSecondaryResourceIdentifier; import io.javaoperatorsdk.operator.processing.event.source.EventSource; @@ -88,6 +88,7 @@ private void createDependentResources(KubernetesClient client) { this.deploymentDR = new KubernetesDependentResource<>() { + @Override protected Deployment desired(WebPage webPage, Context context) { var deploymentName = deploymentName(webPage); @@ -118,6 +119,11 @@ protected boolean match(Deployment actual, Deployment target, Context context) { // todo comparator return true; } + + @Override + protected Class resourceType() { + return Deployment.class; + } }; this.serviceDR = @@ -138,6 +144,11 @@ protected boolean match(Service actual, Service target, Context context) { // todo comparator return true; } + + @Override + protected Class resourceType() { + return Service.class; + } }; }