From a19f5589175a41cede30394abe302ab70ba59a72 Mon Sep 17 00:00:00 2001 From: csviri Date: Fri, 15 Apr 2022 12:47:46 +0200 Subject: [PATCH 01/19] feat: remove primary to secondary mapper (handled automatically) --- .../informer/InformerConfiguration.java | 28 ++------------- .../operator/api/reconciler/Context.java | 7 ++++ .../api/reconciler/DefaultContext.java | 15 ++++++++ .../processing/MultiResourceOwner.java | 23 ++++++++++++ .../KubernetesDependentResource.java | 6 ---- .../source/PrimaryToSecondaryMapper.java | 9 ----- .../source/informer/InformerEventSource.java | 35 ++++++++++++------- .../informer/ManagedInformerEventSource.java | 3 -- .../informer/InformerEventSourceTest.java | 2 ++ .../ConfigMapDependentResource1.java | 10 +----- .../ConfigMapDependentResource2.java | 11 +----- .../dependent/SecretDependentResource.java | 10 +----- .../operator/sample/WebappReconciler.java | 10 ------ .../sample/ConfigMapDependentResource.java | 10 +----- 14 files changed, 77 insertions(+), 102 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/MultiResourceOwner.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/PrimaryToSecondaryMapper.java 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 55d52f42be..28f9c62ee8 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 @@ -8,8 +8,6 @@ import io.javaoperatorsdk.operator.api.config.DefaultResourceConfiguration; import io.javaoperatorsdk.operator.api.config.ResourceConfiguration; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; -import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.PrimaryToSecondaryMapper; import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; @@ -21,19 +19,15 @@ class DefaultInformerConfiguration DefaultResourceConfiguration implements InformerConfiguration { private final SecondaryToPrimaryMapper secondaryToPrimaryMapper; - private final PrimaryToSecondaryMapper

primaryToSecondaryMapper; protected DefaultInformerConfiguration(String labelSelector, Class resourceClass, SecondaryToPrimaryMapper secondaryToPrimaryMapper, - PrimaryToSecondaryMapper

primaryToSecondaryMapper, Set namespaces) { super(labelSelector, resourceClass, namespaces); this.secondaryToPrimaryMapper = Objects.requireNonNullElse(secondaryToPrimaryMapper, Mappers.fromOwnerReference()); - this.primaryToSecondaryMapper = - Objects.requireNonNullElseGet(primaryToSecondaryMapper, () -> ResourceID::fromResource); } @@ -41,21 +35,14 @@ public SecondaryToPrimaryMapper getSecondaryToPrimaryMapper() { return secondaryToPrimaryMapper; } - public PrimaryToSecondaryMapper

getPrimaryToSecondaryMapper() { - return primaryToSecondaryMapper; - } - } SecondaryToPrimaryMapper getSecondaryToPrimaryMapper(); - PrimaryToSecondaryMapper

getPrimaryToSecondaryMapper(); - @SuppressWarnings("unused") class InformerConfigurationBuilder { - private SecondaryToPrimaryMapper secondaryToPrimaryResourcesIdSet; - private PrimaryToSecondaryMapper

associatedWith; + private SecondaryToPrimaryMapper secondaryToPrimaryMapper; private Set namespaces; private String labelSelector; private final Class resourceClass; @@ -66,17 +53,10 @@ private InformerConfigurationBuilder(Class resourceClass) { public InformerConfigurationBuilder withSecondaryToPrimaryMapper( SecondaryToPrimaryMapper secondaryToPrimaryMapper) { - this.secondaryToPrimaryResourcesIdSet = secondaryToPrimaryMapper; + this.secondaryToPrimaryMapper = secondaryToPrimaryMapper; return this; } - public InformerConfigurationBuilder withPrimaryToSecondaryMapper( - PrimaryToSecondaryMapper

associatedWith) { - this.associatedWith = associatedWith; - return this; - } - - public InformerConfigurationBuilder withNamespaces(String... namespaces) { this.namespaces = namespaces != null ? Set.of(namespaces) : Collections.emptySet(); return this; @@ -95,7 +75,7 @@ public InformerConfigurationBuilder withLabelSelector(String labelSelector public InformerConfiguration build() { return new DefaultInformerConfiguration<>(labelSelector, resourceClass, - secondaryToPrimaryResourcesIdSet, associatedWith, + secondaryToPrimaryMapper, namespaces); } } @@ -115,8 +95,6 @@ static InformerConfigurationBuild return new InformerConfigurationBuilder(configuration.getResourceClass()) .withNamespaces(configuration.getNamespaces()) .withLabelSelector(configuration.getLabelSelector()) - .withPrimaryToSecondaryMapper( - configuration.getPrimaryToSecondaryMapper()) .withSecondaryToPrimaryMapper(configuration.getSecondaryToPrimaryMapper()); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java index b2c2270f0b..0aca118706 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java @@ -1,5 +1,6 @@ package io.javaoperatorsdk.operator.api.reconciler; +import java.util.List; import java.util.Optional; import io.fabric8.kubernetes.api.model.HasMetadata; @@ -14,8 +15,14 @@ default Optional getSecondaryResource(Class expectedType) { return getSecondaryResource(expectedType, null); } + default List getSecondaryResources(Class expectedType) { + return getSecondaryResources(expectedType, null); + } + Optional getSecondaryResource(Class expectedType, String eventSourceName); + List getSecondaryResources(Class expectedType, String eventSourceName); + ControllerConfiguration

getControllerConfiguration(); ManagedDependentResourceContext managedDependentResourceContext(); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java index 14fa516b53..485678e13f 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java @@ -1,11 +1,14 @@ package io.javaoperatorsdk.operator.api.reconciler; +import java.util.Collections; +import java.util.List; import java.util.Optional; import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedDependentResourceContext; import io.javaoperatorsdk.operator.processing.Controller; +import io.javaoperatorsdk.operator.processing.MultiResourceOwner; public class DefaultContext

implements Context

{ @@ -35,6 +38,18 @@ public Optional getSecondaryResource(Class expectedType, String eventS .getSecondaryResource(primaryResource); } + @Override + public List getSecondaryResources(Class expectedType, String eventSourceName) { + var eventSource = controller.getEventSourceManager() + .getResourceEventSourceFor(expectedType, eventSourceName); + if (eventSource instanceof MultiResourceOwner) { + return ((MultiResourceOwner) eventSource).getSecondaryResources(primaryResource); + } else { + return eventSource.getSecondaryResource(primaryResource).map(List::of) + .orElse(Collections.EMPTY_LIST); + } + } + @Override public ControllerConfiguration

getControllerConfiguration() { return controllerConfiguration; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/MultiResourceOwner.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/MultiResourceOwner.java new file mode 100644 index 0000000000..d3cc6b3770 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/MultiResourceOwner.java @@ -0,0 +1,23 @@ +package io.javaoperatorsdk.operator.processing; + +import java.util.List; +import java.util.Optional; + +import io.fabric8.kubernetes.api.model.HasMetadata; + +public interface MultiResourceOwner extends ResourceOwner { + + default Optional getSecondaryResource(P primary) { + var list = getSecondaryResources(primary); + if (list.isEmpty()) { + return Optional.empty(); + } else if (list.size() == 1) { + return Optional.of(list.get(0)); + } else { + throw new IllegalStateException("More than 1 secondary resource related to primary"); + } + + } + + List getSecondaryResources(P primary); +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index abf6005597..12f1a76485 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -20,7 +20,6 @@ import io.javaoperatorsdk.operator.processing.dependent.Matcher; import io.javaoperatorsdk.operator.processing.dependent.Matcher.Result; import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.PrimaryToSecondaryMapper; import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; @@ -58,16 +57,11 @@ private void configureWith(String labelSelector, Set namespaces) { final var primaryResourcesRetriever = (this instanceof SecondaryToPrimaryMapper) ? (SecondaryToPrimaryMapper) this : Mappers.fromOwnerReference(); - final PrimaryToSecondaryMapper

secondaryResourceIdentifier = - (this instanceof PrimaryToSecondaryMapper) - ? (PrimaryToSecondaryMapper

) this - : ResourceID::fromResource; InformerConfiguration ic = InformerConfiguration.from(resourceType()) .withLabelSelector(labelSelector) .withNamespaces(namespaces) .withSecondaryToPrimaryMapper(primaryResourcesRetriever) - .withPrimaryToSecondaryMapper(secondaryResourceIdentifier) .build(); configureWith(new InformerEventSource<>(ic, client)); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/PrimaryToSecondaryMapper.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/PrimaryToSecondaryMapper.java deleted file mode 100644 index f0ea122bda..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/PrimaryToSecondaryMapper.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.javaoperatorsdk.operator.processing.event.source; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.processing.event.ResourceID; - -@FunctionalInterface -public interface PrimaryToSecondaryMapper

{ - ResourceID toSecondaryResourceID(P primary); -} 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 b3b1637b94..4a0ad73d61 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 @@ -1,6 +1,7 @@ package io.javaoperatorsdk.operator.processing.event.source.informer; -import java.util.Optional; +import java.util.List; +import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,6 +12,7 @@ import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext; import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationEventFilter; +import io.javaoperatorsdk.operator.processing.MultiResourceOwner; import io.javaoperatorsdk.operator.processing.event.Event; import io.javaoperatorsdk.operator.processing.event.EventHandler; import io.javaoperatorsdk.operator.processing.event.ResourceID; @@ -63,7 +65,9 @@ */ public class InformerEventSource extends ManagedInformerEventSource> - implements ResourceEventHandler, RecentOperationEventFilter { + implements MultiResourceOwner, ResourceEventHandler, RecentOperationEventFilter { + + public static String PRIMARY_TO_SECONDARY_INDEX_NAME = "primaryToSecondary"; private static final Logger log = LoggerFactory.getLogger(InformerEventSource.class); @@ -75,11 +79,20 @@ public InformerEventSource( InformerConfiguration configuration, EventSourceContext

context) { super(context.getClient().resources(configuration.getResourceClass()), configuration); this.configuration = configuration; + initPrimaryToSecondaryIndexer(); } public InformerEventSource(InformerConfiguration configuration, KubernetesClient client) { super(client.resources(configuration.getResourceClass()), configuration); this.configuration = configuration; + initPrimaryToSecondaryIndexer(); + } + + private void initPrimaryToSecondaryIndexer() { + addIndexer(PRIMARY_TO_SECONDARY_INDEX_NAME, r -> { + var resourceIDs = configuration.getSecondaryToPrimaryMapper().toPrimaryResourceIDs(r); + return resourceIDs.stream().map(this::resourceInToKey).collect(Collectors.toList()); + }); } @Override @@ -152,17 +165,15 @@ private void propagateEvent(R object) { }); } - /** - * Retrieves the informed resource associated with the specified primary resource as defined by - * the function provided when this InformerEventSource was created - * - * @param resource the primary resource we want to retrieve the associated resource for - * @return the informed resource associated with the specified primary resource - */ @Override - public Optional getSecondaryResource(P resource) { - final var id = configuration.getPrimaryToSecondaryMapper().toSecondaryResourceID(resource); - return get(id); + public List getSecondaryResources(P primary) { + return byIndex(PRIMARY_TO_SECONDARY_INDEX_NAME, + resourceInToKey(ResourceID.fromResource(primary))); + } + + private String resourceInToKey(ResourceID resourceID) { + return resourceID.getName() + + (resourceID.getNamespace().isEmpty() ? "" : "#" + resourceID.getNamespace().get()); } public InformerConfiguration getConfiguration() { 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 f7007072e9..c6505f45f1 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 @@ -97,9 +97,6 @@ public Optional get(ResourceID resourceID) { } } - @Override - public abstract Optional getSecondaryResource(P primary); - @Override public Optional getCachedValue(ResourceID resourceID) { return get(resourceID); diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java index 96146789f6..4e5ad23e43 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java @@ -13,6 +13,7 @@ import io.fabric8.kubernetes.client.dsl.FilterWatchListMultiDeletable; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.informers.SharedIndexInformer; +import io.fabric8.kubernetes.client.informers.cache.Indexer; import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; import io.javaoperatorsdk.operator.processing.event.EventHandler; import io.javaoperatorsdk.operator.processing.event.ResourceID; @@ -48,6 +49,7 @@ void setup() { when(specificResourceClientMock.withLabelSelector((String) null)) .thenReturn(labeledResourceClientMock); when(labeledResourceClientMock.runnableInformer(0)).thenReturn(informer); + when(informer.getIndexer()).thenReturn(mock(Indexer.class)); when(informerConfiguration.getSecondaryToPrimaryMapper()) .thenReturn(mock(SecondaryToPrimaryMapper.class)); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/orderedmanageddependent/ConfigMapDependentResource1.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/orderedmanageddependent/ConfigMapDependentResource1.java index c0469c6a7c..19fd28b631 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/orderedmanageddependent/ConfigMapDependentResource1.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/orderedmanageddependent/ConfigMapDependentResource1.java @@ -9,13 +9,10 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.ReconcileResult; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUKubernetesDependentResource; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; -import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.PrimaryToSecondaryMapper; @KubernetesDependent(labelSelector = "dependent = cm1") public class ConfigMapDependentResource1 extends - CRUKubernetesDependentResource - implements PrimaryToSecondaryMapper { + CRUKubernetesDependentResource { public ConfigMapDependentResource1() { super(ConfigMap.class); @@ -45,9 +42,4 @@ protected ConfigMap desired(OrderedManagedDependentCustomResource primary, return configMap; } - @Override - public ResourceID toSecondaryResourceID(OrderedManagedDependentCustomResource primary) { - return new ResourceID(primary.getMetadata().getName() + "1", - primary.getMetadata().getNamespace()); - } } diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/orderedmanageddependent/ConfigMapDependentResource2.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/orderedmanageddependent/ConfigMapDependentResource2.java index 40e55d4589..2bffdfa8c1 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/orderedmanageddependent/ConfigMapDependentResource2.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/orderedmanageddependent/ConfigMapDependentResource2.java @@ -9,13 +9,10 @@ import io.javaoperatorsdk.operator.api.reconciler.dependent.ReconcileResult; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUKubernetesDependentResource; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; -import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.PrimaryToSecondaryMapper; @KubernetesDependent(labelSelector = "dependent = cm2") public class ConfigMapDependentResource2 extends - CRUKubernetesDependentResource - implements PrimaryToSecondaryMapper { + CRUKubernetesDependentResource { public ConfigMapDependentResource2() { super(ConfigMap.class); @@ -45,10 +42,4 @@ protected ConfigMap desired(OrderedManagedDependentCustomResource primary, return configMap; } - @Override - public ResourceID toSecondaryResourceID(OrderedManagedDependentCustomResource primary) { - return new ResourceID(primary.getMetadata().getName() + "2", - primary.getMetadata().getNamespace()); - } - } diff --git a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java index 7f39d09130..b1c516df8e 100644 --- a/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java +++ b/sample-operators/mysql-schema/src/main/java/io/javaoperatorsdk/operator/sample/dependent/SecretDependentResource.java @@ -10,12 +10,10 @@ import io.javaoperatorsdk.operator.processing.dependent.Creator; import io.javaoperatorsdk.operator.processing.dependent.Matcher.Result; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResource; -import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.PrimaryToSecondaryMapper; import io.javaoperatorsdk.operator.sample.MySQLSchema; public class SecretDependentResource extends KubernetesDependentResource - implements PrimaryToSecondaryMapper, Creator { + implements Creator { public static final String SECRET_FORMAT = "%s-secret"; public static final String USERNAME_FORMAT = "%s-user"; @@ -57,10 +55,4 @@ public Result match(Secret actual, MySQLSchema primary, Context prepareEventSources(EventSourceContext c .map(ResourceID::fromResource) .collect(Collectors.toSet()); - /* - * We retrieve the Tomcat instance associated with out Webapp from its spec - */ - final PrimaryToSecondaryMapper tomcatFromWebAppSpec = - (Webapp webapp) -> new ResourceID( - webapp.getSpec().getTomcat(), - webapp.getMetadata().getNamespace()); - InformerConfiguration configuration = InformerConfiguration.from(context, Tomcat.class) .withSecondaryToPrimaryMapper(webappsMatchingTomcatName) - .withPrimaryToSecondaryMapper(tomcatFromWebAppSpec) .build(); return EventSourceInitializer .nameEventSources(new InformerEventSource<>(configuration, context)); diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java index 35ceda38c7..de407ae10a 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java @@ -12,16 +12,13 @@ import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUKubernetesDependentResource; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; -import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.PrimaryToSecondaryMapper; import static io.javaoperatorsdk.operator.sample.Utils.configMapName; import static io.javaoperatorsdk.operator.sample.Utils.deploymentName; // this annotation only activates when using managed dependents and is not otherwise needed @KubernetesDependent(labelSelector = WebPageManagedDependentsReconciler.SELECTOR) -class ConfigMapDependentResource extends CRUKubernetesDependentResource - implements PrimaryToSecondaryMapper { +class ConfigMapDependentResource extends CRUKubernetesDependentResource { private static final Logger log = LoggerFactory.getLogger(ConfigMapDependentResource.class); @@ -57,9 +54,4 @@ public ConfigMap update(ConfigMap actual, ConfigMap target, WebPage primary, .delete(); return res; } - - @Override - public ResourceID toSecondaryResourceID(WebPage primary) { - return new ResourceID(configMapName(primary), primary.getMetadata().getNamespace()); - } } From 014a93e6c10faf86ac2fcf8bdfea25916f9e02ac Mon Sep 17 00:00:00 2001 From: csviri Date: Sun, 17 Apr 2022 14:08:26 +0200 Subject: [PATCH 02/19] feat: added integration test --- .../operator/junit/OperatorExtension.java | 2 +- .../operator/ControllerExecutionIT.java | 10 +- .../MultipleSecondaryEventSourceIT.java | 67 +++++++++++ ...pleSecondaryEventSourceCustomResource.java | 17 +++ ...ultipleSecondaryEventSourceReconciler.java | 106 ++++++++++++++++++ .../MultipleSecondaryEventSourceStatus.java | 5 + 6 files changed, 201 insertions(+), 6 deletions(-) create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleSecondaryEventSourceIT.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceCustomResource.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java create mode 100644 operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceStatus.java 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 7602d40295..d95e9466a7 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 @@ -76,7 +76,7 @@ public Reconciler getFirstReconciler() { return reconcilers().findFirst().orElseThrow(); } - public T getControllerOfType(Class type) { + public T getReconcilerOfType(Class type) { return reconcilers() .filter(type::isInstance) .map(type::cast) diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerExecutionIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerExecutionIT.java index 67bc908482..7aeae40622 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerExecutionIT.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/ControllerExecutionIT.java @@ -23,7 +23,7 @@ class ControllerExecutionIT { @Test void configMapGetsCreatedForTestCustomResource() { - operator.getControllerOfType(TestReconciler.class).setUpdateStatus(true); + operator.getReconcilerOfType(TestReconciler.class).setUpdateStatus(true); TestCustomResource resource = TestUtils.testCustomResource(); operator.create(TestCustomResource.class, resource); @@ -35,8 +35,8 @@ void configMapGetsCreatedForTestCustomResource() { @Test void patchesStatusForTestCustomResource() { - operator.getControllerOfType(TestReconciler.class).setPatchStatus(true); - operator.getControllerOfType(TestReconciler.class).setUpdateStatus(true); + operator.getReconcilerOfType(TestReconciler.class).setPatchStatus(true); + operator.getReconcilerOfType(TestReconciler.class).setUpdateStatus(true); TestCustomResource resource = TestUtils.testCustomResource(); operator.create(TestCustomResource.class, resource); @@ -46,7 +46,7 @@ void patchesStatusForTestCustomResource() { @Test void eventIsSkippedChangedOnMetadataOnlyUpdate() { - operator.getControllerOfType(TestReconciler.class).setUpdateStatus(false); + operator.getReconcilerOfType(TestReconciler.class).setUpdateStatus(false); TestCustomResource resource = TestUtils.testCustomResource(); operator.create(TestCustomResource.class, resource); @@ -57,7 +57,7 @@ void eventIsSkippedChangedOnMetadataOnlyUpdate() { @Test void cleanupExecuted() { - operator.getControllerOfType(TestReconciler.class).setUpdateStatus(true); + operator.getReconcilerOfType(TestReconciler.class).setUpdateStatus(true); TestCustomResource resource = TestUtils.testCustomResource(); resource = operator.create(TestCustomResource.class, resource); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleSecondaryEventSourceIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleSecondaryEventSourceIT.java new file mode 100644 index 0000000000..9168b47164 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/MultipleSecondaryEventSourceIT.java @@ -0,0 +1,67 @@ +package io.javaoperatorsdk.operator; + +import java.time.Duration; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.javaoperatorsdk.operator.junit.OperatorExtension; +import io.javaoperatorsdk.operator.sample.multiplesecondaryeventsource.MultipleSecondaryEventSourceCustomResource; +import io.javaoperatorsdk.operator.sample.multiplesecondaryeventsource.MultipleSecondaryEventSourceReconciler; + +import static org.awaitility.Awaitility.await; + +class MultipleSecondaryEventSourceIT { + + public static final String TEST_RESOURCE_NAME = "testresource"; + @RegisterExtension + OperatorExtension operator = + OperatorExtension.builder().withReconciler(MultipleSecondaryEventSourceReconciler.class) + .build(); + + @Test + void receivingPeriodicEvents() { + MultipleSecondaryEventSourceCustomResource resource = createTestCustomResource(); + + operator.create(MultipleSecondaryEventSourceCustomResource.class, resource); + + var reconciler = operator.getReconcilerOfType(MultipleSecondaryEventSourceReconciler.class); + + await().pollDelay(Duration.ofMillis(300)) + .until(() -> reconciler.getNumberOfExecutions() <= 3); + + int numberOfInitialExecutions = reconciler.getNumberOfExecutions(); + + updateConfigMap(resource, 1); + + await().pollDelay(Duration.ofMillis(300)) + .until(() -> reconciler.getNumberOfExecutions() == numberOfInitialExecutions + 1); + + updateConfigMap(resource, 2); + + await().pollDelay(Duration.ofMillis(300)) + .until(() -> reconciler.getNumberOfExecutions() == numberOfInitialExecutions + 2); + } + + private void updateConfigMap(MultipleSecondaryEventSourceCustomResource resource, int number) { + ConfigMap map1 = operator.get(ConfigMap.class, + number == 1 ? MultipleSecondaryEventSourceReconciler.getName1(resource) + : MultipleSecondaryEventSourceReconciler.getName2(resource)); + map1.getData().put("value2", "value2"); + operator.replace(ConfigMap.class, map1); + } + + public MultipleSecondaryEventSourceCustomResource createTestCustomResource() { + MultipleSecondaryEventSourceCustomResource resource = + new MultipleSecondaryEventSourceCustomResource(); + resource.setMetadata( + new ObjectMetaBuilder() + .withName(TEST_RESOURCE_NAME) + .withNamespace(operator.getNamespace()) + .build()); + return resource; + } + +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceCustomResource.java new file mode 100644 index 0000000000..95330ef8b3 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceCustomResource.java @@ -0,0 +1,17 @@ +package io.javaoperatorsdk.operator.sample.multiplesecondaryeventsource; + +import io.fabric8.kubernetes.api.model.Namespaced; +import io.fabric8.kubernetes.client.CustomResource; +import io.fabric8.kubernetes.model.annotation.Group; +import io.fabric8.kubernetes.model.annotation.Kind; +import io.fabric8.kubernetes.model.annotation.ShortNames; +import io.fabric8.kubernetes.model.annotation.Version; + +@Group("sample.javaoperatorsdk") +@Version("v1") +@Kind("MaxIntervalTestCustomResource") +@ShortNames("mit") +public class MultipleSecondaryEventSourceCustomResource + extends CustomResource + implements Namespaced { +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java new file mode 100644 index 0000000000..e8bdf84118 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java @@ -0,0 +1,106 @@ +package io.javaoperatorsdk.operator.sample.multiplesecondaryeventsource; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.kubernetes.client.KubernetesClient; +import io.javaoperatorsdk.operator.api.config.informer.InformerConfiguration; +import io.javaoperatorsdk.operator.api.reconciler.*; +import io.javaoperatorsdk.operator.junit.KubernetesClientAware; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.EventSource; +import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource; +import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider; + +@ControllerConfiguration +public class MultipleSecondaryEventSourceReconciler + implements Reconciler, TestExecutionInfoProvider, + EventSourceInitializer, KubernetesClientAware { + + private final AtomicInteger numberOfExecutions = new AtomicInteger(0); + private KubernetesClient client; + + @Override + public UpdateControl reconcile( + MultipleSecondaryEventSourceCustomResource resource, + Context context) { + numberOfExecutions.addAndGet(1); + + if (client.configMaps().inNamespace(resource.getMetadata().getNamespace()) + .withName(getName1(resource)).get() == null) { + client.configMaps().inNamespace(resource.getMetadata().getNamespace()) + .createOrReplace(configMap(getName1(resource), resource)); + } + if (client.configMaps().inNamespace(resource.getMetadata().getNamespace()) + .withName(getName2(resource)).get() == null) { + client.configMaps().inNamespace(resource.getMetadata().getNamespace()) + .createOrReplace(configMap(getName2(resource), resource)); + } + + if (numberOfExecutions.get() >=3) { + if (context.getSecondaryResources(ConfigMap.class).size() != 2) { + throw new IllegalStateException("There should be 2 related config maps"); + } + } + return UpdateControl.noUpdate(); + } + + public static String getName1(MultipleSecondaryEventSourceCustomResource resource) { + return resource.getMetadata().getName() + "1"; + } + + public static String getName2(MultipleSecondaryEventSourceCustomResource resource) { + return resource.getMetadata().getName() + "2"; + } + + public int getNumberOfExecutions() { + return numberOfExecutions.get(); + } + + @Override + public Map prepareEventSources( + EventSourceContext context) { + + + var config = InformerConfiguration.from(context, ConfigMap.class) + .withNamespaces(context.getControllerConfiguration().getNamespaces()) + .withLabelSelector("multisecondary") + .withSecondaryToPrimaryMapper(s -> { + var name = + s.getMetadata().getName().subSequence(0, s.getMetadata().getName().length() - 1); + return Set.of(new ResourceID(name.toString(), s.getMetadata().getNamespace())); + }).build(); + InformerEventSource configMapEventSource = + new InformerEventSource(config, + context); + return EventSourceInitializer.nameEventSources(configMapEventSource); + } + + ConfigMap configMap(String name, MultipleSecondaryEventSourceCustomResource resource) { + ConfigMap configMap = new ConfigMap(); + configMap.setMetadata(new ObjectMeta()); + configMap.getMetadata().setName(name); + configMap.getMetadata().setNamespace(resource.getMetadata().getNamespace()); + configMap.setData(new HashMap<>()); + configMap.getData().put(name, name); + HashMap labels = new HashMap<>(); + labels.put("multisecondary", "true"); + configMap.getMetadata().setLabels(labels); + configMap.addOwnerReference(resource); + return configMap; + } + + @Override + public KubernetesClient getKubernetesClient() { + return client; + } + + @Override + public void setKubernetesClient(KubernetesClient kubernetesClient) { + this.client = kubernetesClient; + } +} diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceStatus.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceStatus.java new file mode 100644 index 0000000000..2a78bf0531 --- /dev/null +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceStatus.java @@ -0,0 +1,5 @@ +package io.javaoperatorsdk.operator.sample.multiplesecondaryeventsource; + +public class MultipleSecondaryEventSourceStatus { + +} From bc3b1933136f70b3a4d907f4e75e66e6af2161ab Mon Sep 17 00:00:00 2001 From: csviri Date: Sun, 17 Apr 2022 14:11:54 +0200 Subject: [PATCH 03/19] fix: format --- .../MultipleSecondaryEventSourceReconciler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java index e8bdf84118..ce27f0f363 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/multiplesecondaryeventsource/MultipleSecondaryEventSourceReconciler.java @@ -41,7 +41,7 @@ public UpdateControl reconcile( .createOrReplace(configMap(getName2(resource), resource)); } - if (numberOfExecutions.get() >=3) { + if (numberOfExecutions.get() >= 3) { if (context.getSecondaryResources(ConfigMap.class).size() != 2) { throw new IllegalStateException("There should be 2 related config maps"); } From 38a2a66b56a7a4917b850ef8ab4901c1235fae43 Mon Sep 17 00:00:00 2001 From: csviri Date: Sun, 17 Apr 2022 14:20:55 +0200 Subject: [PATCH 04/19] fix: minor issues --- .../operator/sample/ConfigMapDependentResource.java | 10 ++++++++-- .../operator/sample/DeploymentDependentResource.java | 9 +++++++++ .../operator/sample/IngressDependentResource.java | 3 +++ .../operator/sample/ServiceDependentResource.java | 5 +++++ .../java/io/javaoperatorsdk/operator/sample/Utils.java | 1 + 5 files changed, 26 insertions(+), 2 deletions(-) diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java index de407ae10a..518bd5d60e 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java @@ -15,9 +15,10 @@ import static io.javaoperatorsdk.operator.sample.Utils.configMapName; import static io.javaoperatorsdk.operator.sample.Utils.deploymentName; +import static io.javaoperatorsdk.operator.sample.WebPageManagedDependentsReconciler.SELECTOR; // this annotation only activates when using managed dependents and is not otherwise needed -@KubernetesDependent(labelSelector = WebPageManagedDependentsReconciler.SELECTOR) +@KubernetesDependent(labelSelector = SELECTOR) class ConfigMapDependentResource extends CRUKubernetesDependentResource { private static final Logger log = LoggerFactory.getLogger(ConfigMapDependentResource.class); @@ -30,14 +31,19 @@ public ConfigMapDependentResource() { protected ConfigMap desired(WebPage webPage, Context context) { Map data = new HashMap<>(); data.put("index.html", webPage.getSpec().getHtml()); - return new ConfigMapBuilder() + Map labels = new HashMap<>(); + labels.put(SELECTOR, "true"); + ConfigMap configMap = new ConfigMapBuilder() .withMetadata( new ObjectMetaBuilder() .withName(configMapName(webPage)) .withNamespace(webPage.getMetadata().getNamespace()) + .withLabels(labels) .build()) .withData(data) .build(); + configMap.addOwnerReference(webPage); + return configMap; } @Override diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java index ee6322e058..886637384d 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java @@ -1,5 +1,8 @@ package io.javaoperatorsdk.operator.sample; +import java.util.HashMap; +import java.util.Map; + import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.javaoperatorsdk.operator.api.reconciler.Context; @@ -9,6 +12,7 @@ import static io.javaoperatorsdk.operator.ReconcilerUtils.loadYaml; import static io.javaoperatorsdk.operator.sample.Utils.configMapName; import static io.javaoperatorsdk.operator.sample.Utils.deploymentName; +import static io.javaoperatorsdk.operator.sample.WebPageManagedDependentsReconciler.SELECTOR; // this annotation only activates when using managed dependents and is not otherwise needed @KubernetesDependent(labelSelector = WebPageManagedDependentsReconciler.SELECTOR) @@ -20,10 +24,13 @@ public DeploymentDependentResource() { @Override protected Deployment desired(WebPage webPage, Context context) { + Map labels = new HashMap<>(); + labels.put(SELECTOR, "true"); var deploymentName = deploymentName(webPage); Deployment deployment = loadYaml(Deployment.class, getClass(), "deployment.yaml"); deployment.getMetadata().setName(deploymentName); deployment.getMetadata().setNamespace(webPage.getMetadata().getNamespace()); + deployment.getMetadata().setLabels(labels); deployment.getSpec().getSelector().getMatchLabels().put("app", deploymentName); deployment @@ -40,6 +47,8 @@ protected Deployment desired(WebPage webPage, Context context) { .get(0) .setConfigMap( new ConfigMapVolumeSourceBuilder().withName(configMapName(webPage)).build()); + + deployment.addOwnerReference(webPage); return deployment; } } diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/IngressDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/IngressDependentResource.java index a6de51919a..074f36cffb 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/IngressDependentResource.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/IngressDependentResource.java @@ -3,9 +3,12 @@ import io.fabric8.kubernetes.api.model.networking.v1.Ingress; import io.javaoperatorsdk.operator.api.reconciler.Context; import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUKubernetesDependentResource; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent; import static io.javaoperatorsdk.operator.sample.Utils.*; +// this annotation only activates when using managed dependents and is not otherwise needed +@KubernetesDependent(labelSelector = WebPageManagedDependentsReconciler.SELECTOR) public class IngressDependentResource extends CRUKubernetesDependentResource { public IngressDependentResource() { diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java index b501fdb405..5881365247 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java @@ -11,6 +11,7 @@ import static io.javaoperatorsdk.operator.ReconcilerUtils.loadYaml; import static io.javaoperatorsdk.operator.sample.Utils.deploymentName; import static io.javaoperatorsdk.operator.sample.Utils.serviceName; +import static io.javaoperatorsdk.operator.sample.WebPageManagedDependentsReconciler.SELECTOR; // this annotation only activates when using managed dependents and is not otherwise needed @KubernetesDependent(labelSelector = WebPageManagedDependentsReconciler.SELECTOR) @@ -22,12 +23,16 @@ public ServiceDependentResource() { @Override protected Service desired(WebPage webPage, Context context) { + Map serviceLabels = new HashMap<>(); + serviceLabels.put(SELECTOR, "true"); Service service = loadYaml(Service.class, getClass(), "service.yaml"); service.getMetadata().setName(serviceName(webPage)); service.getMetadata().setNamespace(webPage.getMetadata().getNamespace()); + service.getMetadata().setLabels(serviceLabels); Map labels = new HashMap<>(); labels.put("app", deploymentName(webPage)); service.getSpec().setSelector(labels); + service.addOwnerReference(webPage); return service; } } diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/Utils.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/Utils.java index 38d9e68828..e869435c8d 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/Utils.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/Utils.java @@ -59,6 +59,7 @@ static Ingress makeDesiredIngress(WebPage webPage) { Ingress ingress = loadYaml(Ingress.class, Utils.class, "ingress.yaml"); ingress.getMetadata().setName(webPage.getMetadata().getName()); ingress.getMetadata().setNamespace(webPage.getMetadata().getNamespace()); + ingress.addOwnerReference(webPage); ingress.getSpec().getRules().get(0).getHttp().getPaths().get(0) .getBackend().getService().setName(serviceName(webPage)); return ingress; From cd0fefe8aaea1931a5202c81ee515f5122cff08f Mon Sep 17 00:00:00 2001 From: csviri Date: Sun, 17 Apr 2022 15:10:35 +0200 Subject: [PATCH 05/19] minor fix --- .../AbstractEventSourceHolderDependentResource.java | 2 +- .../event/ExternalResourceCachingEventSource.java | 7 +++++++ .../processing/event/source/CachingEventSource.java | 5 ----- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java index baf25aba81..f9dac7bc92 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/AbstractEventSourceHolderDependentResource.java @@ -11,6 +11,7 @@ public abstract class AbstractEventSourceHolderDependentResource> extends AbstractDependentResource implements EventSourceProvider

{ + private T eventSource; private boolean isCacheFillerEventSource; @@ -48,7 +49,6 @@ protected void onUpdated(ResourceID primaryResourceId, R updated, R actual) { } } - @SuppressWarnings("unchecked") private RecentOperationCacheFiller recentOperationCacheFiller() { return (RecentOperationCacheFiller) eventSource; diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ExternalResourceCachingEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ExternalResourceCachingEventSource.java index f69b33dd43..b4bb0f7ef7 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ExternalResourceCachingEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ExternalResourceCachingEventSource.java @@ -1,5 +1,7 @@ package io.javaoperatorsdk.operator.processing.event; +import java.util.Optional; + import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.reconciler.dependent.RecentOperationCacheFiller; import io.javaoperatorsdk.operator.processing.event.source.CachingEventSource; @@ -50,4 +52,9 @@ public synchronized void handleRecentResourceUpdate(ResourceID resourceID, R res } }); } + + @Override + public Optional getSecondaryResource(P primary) { + return cache.get(ResourceID.fromResource(primary)); + } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSource.java index 2ddbf0d54c..8453651b6b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/CachingEventSource.java @@ -51,9 +51,4 @@ public Optional getCachedValue(ResourceID resourceID) { return cache.get(resourceID); } - @Override - public Optional getSecondaryResource(P primary) { - return cache.get(ResourceID.fromResource(primary)); - } - } From c0759e4f8c447e085cf8c509077acc02fddb5c68 Mon Sep 17 00:00:00 2001 From: csviri Date: Sun, 17 Apr 2022 18:19:14 +0200 Subject: [PATCH 06/19] wip --- .../source/SecondaryToPrimaryMapper.java | 4 ++-- .../source/informer/InformerEventSource.java | 2 +- .../informer/PrimaryToSecondaryIndexer.java | 20 +++++++++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndexer.java diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/SecondaryToPrimaryMapper.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/SecondaryToPrimaryMapper.java index 9f4db0c098..45573542c2 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/SecondaryToPrimaryMapper.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/SecondaryToPrimaryMapper.java @@ -5,6 +5,6 @@ import io.javaoperatorsdk.operator.processing.event.ResourceID; @FunctionalInterface -public interface SecondaryToPrimaryMapper { - Set toPrimaryResourceIDs(T dependentResource); +public interface SecondaryToPrimaryMapper { + Set toPrimaryResourceIDs(R dependentResource); } 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 4a0ad73d61..88d04e33ec 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 @@ -173,7 +173,7 @@ public List getSecondaryResources(P primary) { private String resourceInToKey(ResourceID resourceID) { return resourceID.getName() - + (resourceID.getNamespace().isEmpty() ? "" : "#" + resourceID.getNamespace().get()); + + (resourceID.getNamespace().map(ns-> "#" + ns).orElse("")); } public InformerConfiguration getConfiguration() { diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndexer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndexer.java new file mode 100644 index 0000000000..e973e5e4fa --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndexer.java @@ -0,0 +1,20 @@ +package io.javaoperatorsdk.operator.processing.event.source.informer; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; + +import java.util.Map; +import java.util.Set; + +public class PrimaryToSecondaryIndexer { + + private SecondaryToPrimaryMapper secondaryToPrimaryMapper; + private Map> index; + + public PrimaryToSecondaryIndexer(SecondaryToPrimaryMapper secondaryToPrimaryMapper) { + this.secondaryToPrimaryMapper = secondaryToPrimaryMapper; + } + + +} From 28d03565e2bcb7901aa949e9ec5542f1d7733433 Mon Sep 17 00:00:00 2001 From: csviri Date: Sun, 17 Apr 2022 19:10:33 +0200 Subject: [PATCH 07/19] fix: indexing and temp cache --- .../source/informer/InformerEventSource.java | 57 +++++++++++-------- .../informer/ManagedInformerEventSource.java | 12 ---- .../informer/PrimaryToSecondaryIndex.java | 44 ++++++++++++++ .../informer/PrimaryToSecondaryIndexer.java | 20 ------- 4 files changed, 76 insertions(+), 57 deletions(-) create mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java delete mode 100644 operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndexer.java 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 88d04e33ec..3fc96c08a1 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 @@ -1,6 +1,7 @@ package io.javaoperatorsdk.operator.processing.event.source.informer; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import org.slf4j.Logger; @@ -67,32 +68,26 @@ public class InformerEventSource extends ManagedInformerEventSource> implements MultiResourceOwner, ResourceEventHandler, RecentOperationEventFilter { - public static String PRIMARY_TO_SECONDARY_INDEX_NAME = "primaryToSecondary"; - private static final Logger log = LoggerFactory.getLogger(InformerEventSource.class); private final InformerConfiguration configuration; // always called from a synchronized method private final EventRecorder eventRecorder = new EventRecorder<>(); + private final PrimaryToSecondaryIndex primaryToSecondaryIndex; public InformerEventSource( InformerConfiguration configuration, EventSourceContext

context) { super(context.getClient().resources(configuration.getResourceClass()), configuration); this.configuration = configuration; - initPrimaryToSecondaryIndexer(); + primaryToSecondaryIndex = + new PrimaryToSecondaryIndex<>(configuration.getSecondaryToPrimaryMapper()); } public InformerEventSource(InformerConfiguration configuration, KubernetesClient client) { super(client.resources(configuration.getResourceClass()), configuration); this.configuration = configuration; - initPrimaryToSecondaryIndexer(); - } - - private void initPrimaryToSecondaryIndexer() { - addIndexer(PRIMARY_TO_SECONDARY_INDEX_NAME, r -> { - var resourceIDs = configuration.getSecondaryToPrimaryMapper().toPrimaryResourceIDs(r); - return resourceIDs.stream().map(this::resourceInToKey).collect(Collectors.toList()); - }); + primaryToSecondaryIndex = + new PrimaryToSecondaryIndex<>(configuration.getSecondaryToPrimaryMapper()); } @Override @@ -100,6 +95,7 @@ public void onAdd(R resource) { if (log.isDebugEnabled()) { log.debug("On add event received for resource id: {}", ResourceID.fromResource(resource)); } + primaryToSecondaryIndex.onAddOrUpdate(resource); onAddOrUpdate("add", resource, () -> InformerEventSource.super.onAdd(resource)); } @@ -108,10 +104,21 @@ public void onUpdate(R oldObject, R newObject) { if (log.isDebugEnabled()) { log.debug("On update event received for resource id: {}", ResourceID.fromResource(newObject)); } + primaryToSecondaryIndex.onAddOrUpdate(newObject); onAddOrUpdate("update", newObject, () -> InformerEventSource.super.onUpdate(oldObject, newObject)); } + @Override + public void onDelete(R resource, boolean b) { + if (log.isDebugEnabled()) { + log.debug("On delete event received for resource id: {}", ResourceID.fromResource(resource)); + } + primaryToSecondaryIndex.onAddOrUpdate(resource); + super.onDelete(resource, b); + propagateEvent(resource); + } + private synchronized void onAddOrUpdate(String operation, R newObject, Runnable superOnOp) { var resourceID = ResourceID.fromResource(newObject); if (eventRecorder.isRecordingFor(resourceID)) { @@ -135,13 +142,16 @@ private synchronized void onAddOrUpdate(String operation, R newObject, Runnable } } - @Override - public void onDelete(R resource, boolean b) { - if (log.isDebugEnabled()) { - log.debug("On delete event received for resource id: {}", ResourceID.fromResource(resource)); - } - super.onDelete(resource, b); - propagateEvent(resource); + private boolean temporalCacheHasResourceWithVersionAs(R resource) { + var resourceID = ResourceID.fromResource(resource); + var res = temporaryResourceCache.getResourceFromCache(resourceID); + return res.map(r -> { + boolean resVersionsEqual = r.getMetadata().getResourceVersion() + .equals(resource.getMetadata().getResourceVersion()); + log.debug("Resource found in temporal cache for id: {} resource versions equal: {}", + resourceID, resVersionsEqual); + return resVersionsEqual; + }).orElse(false); } private void propagateEvent(R object) { @@ -167,13 +177,9 @@ private void propagateEvent(R object) { @Override public List getSecondaryResources(P primary) { - return byIndex(PRIMARY_TO_SECONDARY_INDEX_NAME, - resourceInToKey(ResourceID.fromResource(primary))); - } - - private String resourceInToKey(ResourceID resourceID) { - return resourceID.getName() - + (resourceID.getNamespace().map(ns-> "#" + ns).orElse("")); + var secondaryIDs = primaryToSecondaryIndex.getSecondaryResources(primary); + return secondaryIDs.stream().map(this::get).flatMap(Optional::stream) + .collect(Collectors.toList()); } public InformerConfiguration getConfiguration() { @@ -194,6 +200,7 @@ public synchronized void handleRecentResourceCreate(ResourceID resourceID, R res } private void handleRecentCreateOrUpdate(R resource, Runnable runnable) { + primaryToSecondaryIndex.onAddOrUpdate(resource); if (eventRecorder.isRecordingFor(ResourceID.fromResource(resource))) { handleRecentResourceOperationAndStopEventRecording(resource); } else { 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 c6505f45f1..606b0bc962 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 @@ -102,18 +102,6 @@ public Optional getCachedValue(ResourceID resourceID) { return get(resourceID); } - protected boolean temporalCacheHasResourceWithVersionAs(R resource) { - var resourceID = ResourceID.fromResource(resource); - var res = temporaryResourceCache.getResourceFromCache(resourceID); - return res.map(r -> { - boolean resVersionsEqual = r.getMetadata().getResourceVersion() - .equals(resource.getMetadata().getResourceVersion()); - log.debug("Resource found in temporal cache for id: {} resource versions equal: {}", - resourceID, resVersionsEqual); - return resVersionsEqual; - }).orElse(false); - } - @Override public Stream list(String namespace, Predicate predicate) { return manager().list(namespace, predicate); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java new file mode 100644 index 0000000000..5d31b7b496 --- /dev/null +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java @@ -0,0 +1,44 @@ +package io.javaoperatorsdk.operator.processing.event.source.informer; + +import java.util.*; + +import io.fabric8.kubernetes.api.model.HasMetadata; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; + +// todo unit test +public class PrimaryToSecondaryIndex { + + private SecondaryToPrimaryMapper secondaryToPrimaryMapper; + private Map> index = new HashMap<>(); + + public PrimaryToSecondaryIndex(SecondaryToPrimaryMapper secondaryToPrimaryMapper) { + this.secondaryToPrimaryMapper = secondaryToPrimaryMapper; + } + + public synchronized void onAddOrUpdate(R resource) { + Set primaryResources = secondaryToPrimaryMapper.toPrimaryResourceIDs(resource); + primaryResources.forEach( + primaryResource -> { + var resourceSet = index.computeIfAbsent(primaryResource, pr -> new HashSet<>()); + resourceSet.add(ResourceID.fromResource(resource)); + }); + } + + public synchronized void onDelete(R resource) { + Set primaryResources = secondaryToPrimaryMapper.toPrimaryResourceIDs(resource); + primaryResources.forEach( + primaryResource -> { + var secondaryResources = index.get(primaryResource); + secondaryResources.remove(ResourceID.fromResource(resource)); + if (secondaryResources.isEmpty()) { + index.remove(primaryResource); + } + }); + } + + public synchronized Set getSecondaryResources(P primary) { + var resourceIDs = index.get(ResourceID.fromResource(primary)); + return Collections.unmodifiableSet(resourceIDs); + } +} diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndexer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndexer.java deleted file mode 100644 index e973e5e4fa..0000000000 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndexer.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.javaoperatorsdk.operator.processing.event.source.informer; - -import io.fabric8.kubernetes.api.model.HasMetadata; -import io.javaoperatorsdk.operator.processing.event.ResourceID; -import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; - -import java.util.Map; -import java.util.Set; - -public class PrimaryToSecondaryIndexer { - - private SecondaryToPrimaryMapper secondaryToPrimaryMapper; - private Map> index; - - public PrimaryToSecondaryIndexer(SecondaryToPrimaryMapper secondaryToPrimaryMapper) { - this.secondaryToPrimaryMapper = secondaryToPrimaryMapper; - } - - -} From c7f56f9e6d536293aed171a56aeed09b3c0a621c Mon Sep 17 00:00:00 2001 From: csviri Date: Sun, 17 Apr 2022 19:14:07 +0200 Subject: [PATCH 08/19] fix: index --- .../event/source/informer/PrimaryToSecondaryIndex.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java index 5d31b7b496..926a017835 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java @@ -39,6 +39,10 @@ public synchronized void onDelete(R resource) { public synchronized Set getSecondaryResources(P primary) { var resourceIDs = index.get(ResourceID.fromResource(primary)); - return Collections.unmodifiableSet(resourceIDs); + if (resourceIDs.isEmpty()) { + return Collections.emptySet(); + } else { + return Collections.unmodifiableSet(resourceIDs); + } } } From bc591cfa4ab0bc191eab98c52a5d46e2a18bf4da Mon Sep 17 00:00:00 2001 From: csviri Date: Sun, 17 Apr 2022 19:19:48 +0200 Subject: [PATCH 09/19] fix: format --- .../event/source/informer/PrimaryToSecondaryIndex.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java index 926a017835..e05ee03f4b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java @@ -6,7 +6,6 @@ import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; -// todo unit test public class PrimaryToSecondaryIndex { private SecondaryToPrimaryMapper secondaryToPrimaryMapper; @@ -40,7 +39,7 @@ public synchronized void onDelete(R resource) { public synchronized Set getSecondaryResources(P primary) { var resourceIDs = index.get(ResourceID.fromResource(primary)); if (resourceIDs.isEmpty()) { - return Collections.emptySet(); + return Collections.emptySet(); } else { return Collections.unmodifiableSet(resourceIDs); } From b56472b632915fd93dff5cb9419cf46de551aafc Mon Sep 17 00:00:00 2001 From: csviri Date: Sun, 17 Apr 2022 19:23:52 +0200 Subject: [PATCH 10/19] fix: index issue --- .../event/source/informer/PrimaryToSecondaryIndex.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java index e05ee03f4b..24da186435 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java @@ -38,7 +38,7 @@ public synchronized void onDelete(R resource) { public synchronized Set getSecondaryResources(P primary) { var resourceIDs = index.get(ResourceID.fromResource(primary)); - if (resourceIDs.isEmpty()) { + if (resourceIDs == null) { return Collections.emptySet(); } else { return Collections.unmodifiableSet(resourceIDs); From ba22186bfc88178d13c8a19e7fee5271bfafeabb Mon Sep 17 00:00:00 2001 From: csviri Date: Sun, 17 Apr 2022 20:18:39 +0200 Subject: [PATCH 11/19] added unit tests --- .../source/informer/InformerEventSource.java | 6 +- .../informer/PrimaryToSecondaryIndex.java | 6 +- .../informer/PrimaryToSecondaryIndexTest.java | 95 +++++++++++++++++++ 3 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndexTest.java 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 3fc96c08a1..096a39d993 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 @@ -73,7 +73,8 @@ public class InformerEventSource private final InformerConfiguration configuration; // always called from a synchronized method private final EventRecorder eventRecorder = new EventRecorder<>(); - private final PrimaryToSecondaryIndex primaryToSecondaryIndex; + // we need direct control for the indexer to propagate the just update resource also to the index + private final PrimaryToSecondaryIndex primaryToSecondaryIndex; public InformerEventSource( InformerConfiguration configuration, EventSourceContext

context) { @@ -177,7 +178,8 @@ private void propagateEvent(R object) { @Override public List getSecondaryResources(P primary) { - var secondaryIDs = primaryToSecondaryIndex.getSecondaryResources(primary); + var secondaryIDs = + primaryToSecondaryIndex.getSecondaryResources(ResourceID.fromResource(primary)); return secondaryIDs.stream().map(this::get).flatMap(Optional::stream) .collect(Collectors.toList()); } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java index 24da186435..cfec133891 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java @@ -6,7 +6,7 @@ import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; -public class PrimaryToSecondaryIndex { +public class PrimaryToSecondaryIndex { private SecondaryToPrimaryMapper secondaryToPrimaryMapper; private Map> index = new HashMap<>(); @@ -36,8 +36,8 @@ public synchronized void onDelete(R resource) { }); } - public synchronized Set getSecondaryResources(P primary) { - var resourceIDs = index.get(ResourceID.fromResource(primary)); + public synchronized Set getSecondaryResources(ResourceID primary) { + var resourceIDs = index.get(primary); if (resourceIDs == null) { return Collections.emptySet(); } else { diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndexTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndexTest.java new file mode 100644 index 0000000000..ca73b135a7 --- /dev/null +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndexTest.java @@ -0,0 +1,95 @@ +package io.javaoperatorsdk.operator.processing.event.source.informer; + +import java.util.Set; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.fabric8.kubernetes.api.model.ConfigMap; +import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.javaoperatorsdk.operator.processing.event.ResourceID; +import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class PrimaryToSecondaryIndexTest { + + private SecondaryToPrimaryMapper secondaryToPrimaryMapperMock = + mock(SecondaryToPrimaryMapper.class); + private PrimaryToSecondaryIndex primaryToSecondaryIndex = + new PrimaryToSecondaryIndex<>(secondaryToPrimaryMapperMock); + + private ResourceID primaryID1 = new ResourceID("id1", "default"); + private ResourceID primaryID2 = new ResourceID("id2", "default"); + private ConfigMap secondary1 = secondary("secondary1"); + private ConfigMap secondary2 = secondary("secondary2"); + + @BeforeEach + void setup() { + when(secondaryToPrimaryMapperMock.toPrimaryResourceIDs(any())) + .thenReturn(Set.of(primaryID1, primaryID2)); + } + + @Test + void returnsEmptySetOnEmptyIndex() { + var res = primaryToSecondaryIndex.getSecondaryResources(ResourceID.fromResource(secondary1)); + assertThat(res).isEmpty(); + } + + @Test + void indexesNewResources() { + primaryToSecondaryIndex.onAddOrUpdate(secondary1); + + var secondaryResources1 = primaryToSecondaryIndex.getSecondaryResources(primaryID1); + var secondaryResources2 = primaryToSecondaryIndex.getSecondaryResources(primaryID2); + + assertThat(secondaryResources1).containsOnly(ResourceID.fromResource(secondary1)); + assertThat(secondaryResources2).containsOnly(ResourceID.fromResource(secondary1)); + } + + @Test + void indexesAdditionalResources() { + primaryToSecondaryIndex.onAddOrUpdate(secondary1); + primaryToSecondaryIndex.onAddOrUpdate(secondary2); + + var secondaryResources1 = primaryToSecondaryIndex.getSecondaryResources(primaryID1); + var secondaryResources2 = primaryToSecondaryIndex.getSecondaryResources(primaryID2); + + assertThat(secondaryResources1).containsOnly(ResourceID.fromResource(secondary1), + ResourceID.fromResource(secondary2)); + assertThat(secondaryResources2).containsOnly(ResourceID.fromResource(secondary1), + ResourceID.fromResource(secondary2)); + } + + @Test + void removingResourceFromIndex() { + primaryToSecondaryIndex.onAddOrUpdate(secondary1); + primaryToSecondaryIndex.onAddOrUpdate(secondary2); + primaryToSecondaryIndex.onDelete(secondary1); + + var secondaryResources1 = primaryToSecondaryIndex.getSecondaryResources(primaryID1); + var secondaryResources2 = primaryToSecondaryIndex.getSecondaryResources(primaryID2); + + assertThat(secondaryResources1).containsOnly(ResourceID.fromResource(secondary2)); + assertThat(secondaryResources2).containsOnly(ResourceID.fromResource(secondary2)); + + primaryToSecondaryIndex.onDelete(secondary2); + + secondaryResources1 = primaryToSecondaryIndex.getSecondaryResources(primaryID1); + secondaryResources2 = primaryToSecondaryIndex.getSecondaryResources(primaryID2); + + assertThat(secondaryResources1).isEmpty(); + assertThat(secondaryResources2).isEmpty(); + } + + ConfigMap secondary(String name) { + ConfigMap configMap = new ConfigMap(); + configMap.setMetadata(new ObjectMeta()); + configMap.getMetadata().setName(name); + configMap.getMetadata().setNamespace("default"); + return configMap; + } +} From 8bd61fc82d0e57ffe07d66f994cca441db137789 Mon Sep 17 00:00:00 2001 From: csviri Date: Sun, 17 Apr 2022 22:12:49 +0200 Subject: [PATCH 12/19] fix: get secondary resources --- .../operator/api/reconciler/Context.java | 8 ++--- .../api/reconciler/DefaultContext.java | 33 ++++++++++++++++--- .../processing/event/EventSourceManager.java | 5 +++ .../processing/event/EventSources.java | 14 ++++++-- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java index 0aca118706..a3717b3c1d 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java @@ -15,14 +15,12 @@ default Optional getSecondaryResource(Class expectedType) { return getSecondaryResource(expectedType, null); } - default List getSecondaryResources(Class expectedType) { - return getSecondaryResources(expectedType, null); - } - - Optional getSecondaryResource(Class expectedType, String eventSourceName); + List getSecondaryResources(Class expectedType); List getSecondaryResources(Class expectedType, String eventSourceName); + Optional getSecondaryResource(Class expectedType, String eventSourceName); + ControllerConfiguration

getControllerConfiguration(); ManagedDependentResourceContext managedDependentResourceContext(); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java index 485678e13f..8313ecbce8 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java @@ -3,6 +3,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; import io.fabric8.kubernetes.api.model.HasMetadata; import io.javaoperatorsdk.operator.api.config.ControllerConfiguration; @@ -31,22 +32,44 @@ public Optional getRetryInfo() { return Optional.ofNullable(retryInfo); } + @Override + @SuppressWarnings("unchecked") + public List getSecondaryResources(Class expectedType) { + return controller.getEventSourceManager().getEventSourcesFor(expectedType).stream() + .map( + es -> { + if (es instanceof MultiResourceOwner) { + return ((MultiResourceOwner) es).getSecondaryResources(primaryResource); + } else { + return es.getSecondaryResource(primaryResource) + .map(List::of) + .orElse(Collections.emptyList()); + } + }) + .flatMap(List::stream) + .collect(Collectors.toList()); + } + @Override public Optional getSecondaryResource(Class expectedType, String eventSourceName) { - return controller.getEventSourceManager() + return controller + .getEventSourceManager() .getResourceEventSourceFor(expectedType, eventSourceName) .getSecondaryResource(primaryResource); } @Override + @SuppressWarnings("unchecked") public List getSecondaryResources(Class expectedType, String eventSourceName) { - var eventSource = controller.getEventSourceManager() - .getResourceEventSourceFor(expectedType, eventSourceName); + var eventSource = + controller.getEventSourceManager().getResourceEventSourceFor(expectedType, eventSourceName); if (eventSource instanceof MultiResourceOwner) { return ((MultiResourceOwner) eventSource).getSecondaryResources(primaryResource); } else { - return eventSource.getSecondaryResource(primaryResource).map(List::of) - .orElse(Collections.EMPTY_LIST); + return eventSource + .getSecondaryResource(primaryResource) + .map(List::of) + .orElse(Collections.emptyList()); } } diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java index da42a1e1e7..1ccc0ad2d9 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSourceManager.java @@ -1,6 +1,7 @@ package io.javaoperatorsdk.operator.processing.event; import java.util.LinkedHashSet; +import java.util.List; import java.util.Objects; import java.util.Set; import java.util.concurrent.locks.ReentrantLock; @@ -176,6 +177,10 @@ ResourceEventSource getResourceEventSourceFor( return getResourceEventSourceFor(dependentType, null); } + public List> getEventSourcesFor(Class dependentType) { + return eventSources.getEventSources(dependentType); + } + public ResourceEventSource getResourceEventSourceFor( Class dependentType, String qualifier) { Objects.requireNonNull(dependentType, "dependentType is Mandatory"); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSources.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSources.java index 8ba4682da3..1d2d343831 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSources.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/EventSources.java @@ -1,10 +1,9 @@ package io.javaoperatorsdk.operator.processing.event; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; +import java.util.*; import java.util.concurrent.ConcurrentNavigableMap; import java.util.concurrent.ConcurrentSkipListMap; +import java.util.stream.Collectors; import java.util.stream.Stream; import io.fabric8.kubernetes.api.model.HasMetadata; @@ -131,4 +130,13 @@ private String keyAsString(Class dependentType, String name) { ? "(" + dependentType.getName() + ", " + name + ")" : dependentType.getName(); } + + @SuppressWarnings("unchecked") + public List> getEventSources(Class dependentType) { + final var sourcesForType = sources.get(keyFor(dependentType)); + return sourcesForType.values().stream() + .filter(ResourceEventSource.class::isInstance) + .map(es -> (ResourceEventSource) es) + .collect(Collectors.toList()); + } } From 6249306227e6db32e2ab7b81617aae3e12d589e4 Mon Sep 17 00:00:00 2001 From: csviri Date: Sun, 17 Apr 2022 22:27:56 +0200 Subject: [PATCH 13/19] generics improvements --- .../api/config/informer/InformerConfiguration.java | 8 ++++---- .../kubernetes/KubernetesDependentResource.java | 2 +- .../event/source/informer/InformerEventSource.java | 10 +++++----- .../event/source/informer/InformerEventSourceTest.java | 2 +- .../CreateUpdateEventFilterTestReconciler.java | 2 +- .../InformerEventSourceTestCustomReconciler.java | 2 +- .../operator/sample/WebappReconciler.java | 2 +- .../operator/sample/WebPageReconciler.java | 5 ++--- 8 files changed, 16 insertions(+), 17 deletions(-) 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 28f9c62ee8..f0ad2797e6 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 @@ -12,11 +12,11 @@ import io.javaoperatorsdk.operator.processing.event.source.informer.Mappers; @SuppressWarnings("rawtypes") -public interface InformerConfiguration +public interface InformerConfiguration extends ResourceConfiguration { class DefaultInformerConfiguration extends - DefaultResourceConfiguration implements InformerConfiguration { + DefaultResourceConfiguration implements InformerConfiguration { private final SecondaryToPrimaryMapper secondaryToPrimaryMapper; @@ -73,7 +73,7 @@ public InformerConfigurationBuilder withLabelSelector(String labelSelector return this; } - public InformerConfiguration build() { + public InformerConfiguration build() { return new DefaultInformerConfiguration<>(labelSelector, resourceClass, secondaryToPrimaryMapper, namespaces); @@ -91,7 +91,7 @@ static InformerConfigurationBuilder from(Class resourceClass) { } static InformerConfigurationBuilder from( - InformerConfiguration configuration) { + InformerConfiguration configuration) { return new InformerConfigurationBuilder(configuration.getResourceClass()) .withNamespaces(configuration.getNamespaces()) .withLabelSelector(configuration.getLabelSelector()) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java index 12f1a76485..b5dd2a720a 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java @@ -57,7 +57,7 @@ private void configureWith(String labelSelector, Set namespaces) { final var primaryResourcesRetriever = (this instanceof SecondaryToPrimaryMapper) ? (SecondaryToPrimaryMapper) this : Mappers.fromOwnerReference(); - InformerConfiguration ic = + InformerConfiguration ic = InformerConfiguration.from(resourceType()) .withLabelSelector(labelSelector) .withNamespaces(namespaces) 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 096a39d993..986c919722 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 @@ -65,26 +65,26 @@ * @param

type of the primary resource */ public class InformerEventSource - extends ManagedInformerEventSource> + extends ManagedInformerEventSource> implements MultiResourceOwner, ResourceEventHandler, RecentOperationEventFilter { private static final Logger log = LoggerFactory.getLogger(InformerEventSource.class); - private final InformerConfiguration configuration; + private final InformerConfiguration configuration; // always called from a synchronized method private final EventRecorder eventRecorder = new EventRecorder<>(); // we need direct control for the indexer to propagate the just update resource also to the index private final PrimaryToSecondaryIndex primaryToSecondaryIndex; public InformerEventSource( - InformerConfiguration configuration, EventSourceContext

context) { + InformerConfiguration configuration, EventSourceContext

context) { super(context.getClient().resources(configuration.getResourceClass()), configuration); this.configuration = configuration; primaryToSecondaryIndex = new PrimaryToSecondaryIndex<>(configuration.getSecondaryToPrimaryMapper()); } - public InformerEventSource(InformerConfiguration configuration, KubernetesClient client) { + public InformerEventSource(InformerConfiguration configuration, KubernetesClient client) { super(client.resources(configuration.getResourceClass()), configuration); this.configuration = configuration; primaryToSecondaryIndex = @@ -184,7 +184,7 @@ public List getSecondaryResources(P primary) { .collect(Collectors.toList()); } - public InformerConfiguration getConfiguration() { + public InformerConfiguration getConfiguration() { return configuration; } diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java index 4e5ad23e43..7ac6779523 100644 --- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java +++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/source/informer/InformerEventSourceTest.java @@ -39,7 +39,7 @@ class InformerEventSourceTest { mock(FilterWatchListMultiDeletable.class); private FilterWatchListDeletable labeledResourceClientMock = mock(FilterWatchListDeletable.class); private SharedIndexInformer informer = mock(SharedIndexInformer.class); - private InformerConfiguration informerConfiguration = + private InformerConfiguration informerConfiguration = mock(InformerConfiguration.class); @BeforeEach diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java index aa50e5fa4f..acfc109f72 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/createupdateeventfilter/CreateUpdateEventFilterTestReconciler.java @@ -101,7 +101,7 @@ private ConfigMap createConfigMap(CreateUpdateEventFilterTestCustomResource reso @Override public Map prepareEventSources( EventSourceContext context) { - InformerConfiguration informerConfiguration = + InformerConfiguration informerConfiguration = InformerConfiguration.from(context, ConfigMap.class) .withLabelSelector("integrationtest = " + this.getClass().getSimpleName()) .build(); diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java index ebcbf85994..a4aa0f4ddd 100644 --- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java +++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/informereventsource/InformerEventSourceTestCustomReconciler.java @@ -41,7 +41,7 @@ public class InformerEventSourceTestCustomReconciler public Map prepareEventSources( EventSourceContext context) { - InformerConfiguration config = + InformerConfiguration config = InformerConfiguration.from(context, ConfigMap.class) .withSecondaryToPrimaryMapper(Mappers.fromAnnotation(RELATED_RESOURCE_NAME)) .build(); diff --git a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/WebappReconciler.java b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/WebappReconciler.java index 6bd5618a97..697f72cfdd 100644 --- a/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/WebappReconciler.java +++ b/sample-operators/tomcat-operator/src/main/java/io/javaoperatorsdk/operator/sample/WebappReconciler.java @@ -58,7 +58,7 @@ public Map prepareEventSources(EventSourceContext c .map(ResourceID::fromResource) .collect(Collectors.toSet()); - InformerConfiguration configuration = + InformerConfiguration configuration = InformerConfiguration.from(context, Tomcat.class) .withSecondaryToPrimaryMapper(webappsMatchingTomcatName) .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 7f8f38afb8..5bccefb56e 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 @@ -66,8 +66,7 @@ public Map prepareEventSources(EventSourceContext new InformerEventSource<>(InformerConfiguration.from(context, Ingress.class) .withLabelSelector(LOW_LEVEL_LABEL_KEY) .build(), context); - return EventSourceInitializer.nameEventSources(configMapEventSource, - deploymentEventSource, + return EventSourceInitializer.nameEventSources(configMapEventSource, deploymentEventSource, serviceEventSource, ingressEventSource); } @@ -208,7 +207,7 @@ private Deployment makeDesiredDeployment(WebPage webPage, String deploymentName, private ConfigMap makeDesiredHtmlConfigMap(String ns, String configMapName, WebPage webPage) { Map data = new HashMap<>(); - data.put("index.html", webPage.getSpec().getHtml()); + data.put(INDEX_HTML, webPage.getSpec().getHtml()); ConfigMap configMap = new ConfigMapBuilder() .withMetadata( From e5c8dccfbc77f1e839e1ae2f1235150bb7f9ec41 Mon Sep 17 00:00:00 2001 From: csviri Date: Sun, 17 Apr 2022 22:31:24 +0200 Subject: [PATCH 14/19] smell fix --- .../operator/api/config/informer/InformerConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f0ad2797e6..3ec615ffcb 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 @@ -15,7 +15,7 @@ public interface InformerConfiguration extends ResourceConfiguration { - class DefaultInformerConfiguration extends + class DefaultInformerConfiguration extends DefaultResourceConfiguration implements InformerConfiguration { private final SecondaryToPrimaryMapper secondaryToPrimaryMapper; From 93e11a6591bc44fdb14cb7a761a6b86015a36130 Mon Sep 17 00:00:00 2001 From: csviri Date: Mon, 18 Apr 2022 19:15:06 +0200 Subject: [PATCH 15/19] fix: revert explicit owner refereces --- .../operator/sample/DeploymentDependentResource.java | 8 +++----- .../operator/sample/ConfigMapDependentResource.java | 1 - .../operator/sample/DeploymentDependentResource.java | 1 - .../operator/sample/ServiceDependentResource.java | 1 - .../java/io/javaoperatorsdk/operator/sample/Utils.java | 1 - 5 files changed, 3 insertions(+), 9 deletions(-) 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 1e0c7c08d1..94726d40ae 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 @@ -5,14 +5,12 @@ import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder; import io.javaoperatorsdk.operator.ReconcilerUtils; import io.javaoperatorsdk.operator.api.reconciler.Context; -import io.javaoperatorsdk.operator.processing.dependent.Creator; -import io.javaoperatorsdk.operator.processing.dependent.Updater; +import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUKubernetesDependentResource; 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 - implements Creator, Updater { +public class DeploymentDependentResource + extends CRUKubernetesDependentResource { public DeploymentDependentResource() { super(Deployment.class); diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java index 518bd5d60e..d80291a3f8 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java @@ -42,7 +42,6 @@ protected ConfigMap desired(WebPage webPage, Context context) { .build()) .withData(data) .build(); - configMap.addOwnerReference(webPage); return configMap; } diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java index 886637384d..80a41e24d8 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/DeploymentDependentResource.java @@ -48,7 +48,6 @@ protected Deployment desired(WebPage webPage, Context context) { .setConfigMap( new ConfigMapVolumeSourceBuilder().withName(configMapName(webPage)).build()); - deployment.addOwnerReference(webPage); return deployment; } } diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java index 5881365247..84d670cfc5 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ServiceDependentResource.java @@ -32,7 +32,6 @@ protected Service desired(WebPage webPage, Context context) { Map labels = new HashMap<>(); labels.put("app", deploymentName(webPage)); service.getSpec().setSelector(labels); - service.addOwnerReference(webPage); return service; } } diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/Utils.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/Utils.java index e869435c8d..38d9e68828 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/Utils.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/Utils.java @@ -59,7 +59,6 @@ static Ingress makeDesiredIngress(WebPage webPage) { Ingress ingress = loadYaml(Ingress.class, Utils.class, "ingress.yaml"); ingress.getMetadata().setName(webPage.getMetadata().getName()); ingress.getMetadata().setNamespace(webPage.getMetadata().getNamespace()); - ingress.addOwnerReference(webPage); ingress.getSpec().getRules().get(0).getHttp().getPaths().get(0) .getBackend().getService().setName(serviceName(webPage)); return ingress; From dfc2253d8b9c4210e4276dd0bab70963682aec96 Mon Sep 17 00:00:00 2001 From: csviri Date: Mon, 18 Apr 2022 19:25:58 +0200 Subject: [PATCH 16/19] remove smell --- .../operator/sample/ConfigMapDependentResource.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java index d80291a3f8..bba817436c 100644 --- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java +++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/ConfigMapDependentResource.java @@ -33,7 +33,7 @@ protected ConfigMap desired(WebPage webPage, Context context) { data.put("index.html", webPage.getSpec().getHtml()); Map labels = new HashMap<>(); labels.put(SELECTOR, "true"); - ConfigMap configMap = new ConfigMapBuilder() + return new ConfigMapBuilder() .withMetadata( new ObjectMetaBuilder() .withName(configMapName(webPage)) @@ -42,7 +42,6 @@ protected ConfigMap desired(WebPage webPage, Context context) { .build()) .withData(data) .build(); - return configMap; } @Override From 867b3cb66f33f42a006cf75f25d1a9cdd8cfef03 Mon Sep 17 00:00:00 2001 From: csviri Date: Tue, 19 Apr 2022 10:38:06 +0200 Subject: [PATCH 17/19] fix: remove get secondary resources by name --- .../operator/api/reconciler/Context.java | 2 -- .../operator/api/reconciler/DefaultContext.java | 15 --------------- 2 files changed, 17 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java index a3717b3c1d..ab7ebbb29b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java @@ -17,8 +17,6 @@ default Optional getSecondaryResource(Class expectedType) { List getSecondaryResources(Class expectedType); - List getSecondaryResources(Class expectedType, String eventSourceName); - Optional getSecondaryResource(Class expectedType, String eventSourceName); ControllerConfiguration

getControllerConfiguration(); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java index 8313ecbce8..2c6a663465 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java @@ -58,21 +58,6 @@ public Optional getSecondaryResource(Class expectedType, String eventS .getSecondaryResource(primaryResource); } - @Override - @SuppressWarnings("unchecked") - public List getSecondaryResources(Class expectedType, String eventSourceName) { - var eventSource = - controller.getEventSourceManager().getResourceEventSourceFor(expectedType, eventSourceName); - if (eventSource instanceof MultiResourceOwner) { - return ((MultiResourceOwner) eventSource).getSecondaryResources(primaryResource); - } else { - return eventSource - .getSecondaryResource(primaryResource) - .map(List::of) - .orElse(Collections.emptyList()); - } - } - @Override public ControllerConfiguration

getControllerConfiguration() { return controllerConfiguration; From 69af2729a9590425a316829574e2ee40e48020e9 Mon Sep 17 00:00:00 2001 From: csviri Date: Tue, 19 Apr 2022 15:10:24 +0200 Subject: [PATCH 18/19] code review fixes --- .../io/javaoperatorsdk/operator/api/reconciler/Context.java | 4 ++-- .../operator/api/reconciler/DefaultContext.java | 5 +++-- .../event/source/informer/InformerEventSource.java | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java index ab7ebbb29b..845810c8a1 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java @@ -1,7 +1,7 @@ package io.javaoperatorsdk.operator.api.reconciler; -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.ControllerConfiguration; @@ -15,7 +15,7 @@ default Optional getSecondaryResource(Class expectedType) { return getSecondaryResource(expectedType, null); } - List getSecondaryResources(Class expectedType); + Set getSecondaryResources(Class expectedType); Optional getSecondaryResource(Class expectedType, String eventSourceName); diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java index 2c6a663465..00a94390c6 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java @@ -3,6 +3,7 @@ import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import io.fabric8.kubernetes.api.model.HasMetadata; @@ -34,7 +35,7 @@ public Optional getRetryInfo() { @Override @SuppressWarnings("unchecked") - public List getSecondaryResources(Class expectedType) { + public Set getSecondaryResources(Class expectedType) { return controller.getEventSourceManager().getEventSourcesFor(expectedType).stream() .map( es -> { @@ -47,7 +48,7 @@ public List getSecondaryResources(Class expectedType) { } }) .flatMap(List::stream) - .collect(Collectors.toList()); + .collect(Collectors.toSet()); } @Override 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 986c919722..08facecbb7 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 @@ -115,7 +115,7 @@ public void onDelete(R resource, boolean b) { if (log.isDebugEnabled()) { log.debug("On delete event received for resource id: {}", ResourceID.fromResource(resource)); } - primaryToSecondaryIndex.onAddOrUpdate(resource); + primaryToSecondaryIndex.onDelete(resource); super.onDelete(resource, b); propagateEvent(resource); } @@ -127,7 +127,7 @@ private synchronized void onAddOrUpdate(String operation, R newObject, Runnable eventRecorder.recordEvent(newObject); return; } - if (temporalCacheHasResourceWithVersionAs(newObject)) { + if (temporaryCacheHasResourceWithSameVersionAs(newObject)) { log.debug( "Skipping event propagation for {}, since was a result of a reconcile action. Resource ID: {}", operation, @@ -143,7 +143,7 @@ private synchronized void onAddOrUpdate(String operation, R newObject, Runnable } } - private boolean temporalCacheHasResourceWithVersionAs(R resource) { + private boolean temporaryCacheHasResourceWithSameVersionAs(R resource) { var resourceID = ResourceID.fromResource(resource); var res = temporaryResourceCache.getResourceFromCache(resourceID); return res.map(r -> { From e43cec59d7d97e92045a37e8ac3c0e8bb43314bb Mon Sep 17 00:00:00 2001 From: csviri Date: Tue, 19 Apr 2022 17:46:42 +0200 Subject: [PATCH 19/19] fixed comment from CR --- .../event/source/informer/PrimaryToSecondaryIndex.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java index cfec133891..d83b60827b 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/source/informer/PrimaryToSecondaryIndex.java @@ -6,7 +6,7 @@ import io.javaoperatorsdk.operator.processing.event.ResourceID; import io.javaoperatorsdk.operator.processing.event.source.SecondaryToPrimaryMapper; -public class PrimaryToSecondaryIndex { +class PrimaryToSecondaryIndex { private SecondaryToPrimaryMapper secondaryToPrimaryMapper; private Map> index = new HashMap<>();