Skip to content

improve: secondaryToPrimary check type of owner reference #2371

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ public List<EventSource> prepareEventSources(
var es = new InformerEventSource<>(InformerConfiguration.from(ConfigMap.class, context)
.withItemStore(boundedItemStore)
.withSecondaryToPrimaryMapper(
Mappers.fromOwnerReference(this instanceof BoundedCacheClusterScopeTestReconciler))
Mappers.fromOwnerReferences(context.getPrimaryResourceClass(),
this instanceof BoundedCacheClusterScopeTestReconciler))
.build(), context);

return List.of(es);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ protected DefaultInformerConfiguration(String labelSelector,
this.followControllerNamespaceChanges = followControllerNamespaceChanges;
this.groupVersionKind = groupVersionKind;
this.primaryToSecondaryMapper = primaryToSecondaryMapper;
this.secondaryToPrimaryMapper =
Objects.requireNonNullElse(secondaryToPrimaryMapper,
Mappers.fromOwnerReferences(false));
this.secondaryToPrimaryMapper = secondaryToPrimaryMapper;
this.onDeleteFilter = onDeleteFilter;
}

Expand Down Expand Up @@ -135,16 +133,24 @@ class InformerConfigurationBuilder<R extends HasMetadata> {
private boolean inheritControllerNamespacesOnChange = false;
private ItemStore<R> itemStore;
private Long informerListLimit;
private final Class<? extends HasMetadata> primaryResourceClass;

private InformerConfigurationBuilder(Class<R> resourceClass) {
this.resourceClass = resourceClass;
this.groupVersionKind = null;
private InformerConfigurationBuilder(Class<R> resourceClass,
Class<? extends HasMetadata> primaryResourceClass) {
this(resourceClass, primaryResourceClass, null);
}

@SuppressWarnings("unchecked")
private InformerConfigurationBuilder(GroupVersionKind groupVersionKind) {
this.resourceClass = (Class<R>) GenericKubernetesResource.class;
private InformerConfigurationBuilder(GroupVersionKind groupVersionKind,
Class<? extends HasMetadata> primaryResourceClass) {
this((Class<R>) GenericKubernetesResource.class, primaryResourceClass, groupVersionKind);
}

private InformerConfigurationBuilder(Class<R> resourceClass,
Class<? extends HasMetadata> primaryResourceClass, GroupVersionKind groupVersionKind) {
this.resourceClass = resourceClass;
this.groupVersionKind = groupVersionKind;
this.primaryResourceClass = primaryResourceClass;
}

public <P extends HasMetadata> InformerConfigurationBuilder<R> withPrimaryToSecondaryMapper(
Expand Down Expand Up @@ -264,23 +270,17 @@ public InformerConfigurationBuilder<R> withInformerListLimit(Long informerListLi
public InformerConfiguration<R> build() {
return new DefaultInformerConfiguration<>(labelSelector, resourceClass, groupVersionKind,
primaryToSecondaryMapper,
secondaryToPrimaryMapper,
Objects.requireNonNullElse(secondaryToPrimaryMapper,
Mappers.fromOwnerReferences(HasMetadata.getApiVersion(primaryResourceClass),
HasMetadata.getKind(primaryResourceClass), false)),
namespaces, inheritControllerNamespacesOnChange, onAddFilter, onUpdateFilter,
onDeleteFilter, genericFilter, itemStore, informerListLimit);
}
}

static <R extends HasMetadata> InformerConfigurationBuilder<R> from(
Class<R> resourceClass) {
return new InformerConfigurationBuilder<>(resourceClass);
}

/**
* * For the case when want to use {@link GenericKubernetesResource}
*/
static <R extends HasMetadata> InformerConfigurationBuilder<R> from(
GroupVersionKind groupVersionKind) {
return new InformerConfigurationBuilder<>(groupVersionKind);
Class<R> resourceClass, Class<? extends HasMetadata> primaryResourceClass) {
return new InformerConfigurationBuilder<>(resourceClass, primaryResourceClass);
}

/**
Expand All @@ -294,20 +294,26 @@ static <R extends HasMetadata> InformerConfigurationBuilder<R> from(
*/
static <R extends HasMetadata> InformerConfigurationBuilder<R> from(
Class<R> resourceClass, EventSourceContext<?> eventSourceContext) {
return new InformerConfigurationBuilder<>(resourceClass)
return new InformerConfigurationBuilder<>(resourceClass,
eventSourceContext.getPrimaryResourceClass())
.withNamespacesInheritedFromController(eventSourceContext);
}

/**
* * For the case when want to use {@link GenericKubernetesResource}
* For the case when want to use {@link GenericKubernetesResource}
*/
@SuppressWarnings("unchecked")
static InformerConfigurationBuilder<GenericKubernetesResource> from(
GroupVersionKind groupVersionKind, EventSourceContext<?> eventSourceContext) {
return new InformerConfigurationBuilder<GenericKubernetesResource>(groupVersionKind)
return new InformerConfigurationBuilder<GenericKubernetesResource>(groupVersionKind,
eventSourceContext.getPrimaryResourceClass())
.withNamespacesInheritedFromController(eventSourceContext);
}

static InformerConfigurationBuilder<GenericKubernetesResource> from(
GroupVersionKind groupVersionKind, Class<? extends HasMetadata> primaryResourceClass) {
return new InformerConfigurationBuilder<>(groupVersionKind, primaryResourceClass);
}

@SuppressWarnings("unchecked")
@Override
default Class<R> getResourceClass() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@ public class EventSourceContext<P extends HasMetadata> {
private final IndexerResourceCache<P> primaryCache;
private final ControllerConfiguration<P> controllerConfiguration;
private final KubernetesClient client;
private final Class<P> primaryResourceClass;

public EventSourceContext(IndexerResourceCache<P> primaryCache,
ControllerConfiguration<P> controllerConfiguration,
KubernetesClient client) {
KubernetesClient client,
Class<P> primaryResourceClass) {
this.primaryCache = primaryCache;
this.controllerConfiguration = controllerConfiguration;
this.client = client;
this.primaryResourceClass = primaryResourceClass;
}

/**
Expand Down Expand Up @@ -54,4 +57,8 @@ public ControllerConfiguration<P> getControllerConfiguration() {
public KubernetesClient getClient() {
return client;
}

public Class<P> getPrimaryResourceClass() {
return primaryResourceClass;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ public Controller(Reconciler<P> reconciler,
eventSourceManager.postProcessDefaultEventSourcesAfterProcessorInitializer();
controllerHealthInfo = new ControllerHealthInfo(eventSourceManager);
eventSourceContext = new EventSourceContext<>(
eventSourceManager.getControllerEventSource(), configuration, kubernetesClient);
eventSourceManager.getControllerEventSource(), configuration, kubernetesClient,
configuration.getResourceClass());
initAndRegisterEventSources(eventSourceContext);
configurationService.getMetrics().controllerRegistered(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public GenericKubernetesDependentResource(GroupVersionKind groupVersionKind) {
}

protected InformerConfiguration.InformerConfigurationBuilder<GenericKubernetesResource> informerConfigurationBuilder() {
return InformerConfiguration.from(groupVersionKind);
return InformerConfiguration.from(groupVersionKind, getPrimaryResourceType());
}

@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,15 @@ private void configureWith(String labelSelector, Set<String> namespaces,

// just to seamlessly handle GenericKubernetesDependentResource
protected InformerConfiguration.InformerConfigurationBuilder<R> informerConfigurationBuilder() {
return InformerConfiguration.from(resourceType());
return InformerConfiguration.from(resourceType(), getPrimaryResourceType());
}

@SuppressWarnings("unchecked")
private SecondaryToPrimaryMapper<R> getSecondaryToPrimaryMapper() {
if (this instanceof SecondaryToPrimaryMapper) {
return (SecondaryToPrimaryMapper<R>) this;
} else if (garbageCollected) {
return Mappers.fromOwnerReferences(clustered);
return Mappers.fromOwnerReferences(getPrimaryResourceType(), clustered);
} else if (useNonOwnerRefBasedSecondaryToPrimaryMapping()) {
return Mappers.fromDefaultAnnotations();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,6 @@ public static ResourceID fromResource(HasMetadata resource) {
resource.getMetadata().getNamespace());
}

public static Optional<ResourceID> fromFirstOwnerReference(HasMetadata resource) {
return fromFirstOwnerReference(resource, false);
}

public static Optional<ResourceID> fromFirstOwnerReference(HasMetadata resource,
boolean clusterScoped) {
var ownerReferences = resource.getMetadata().getOwnerReferences();
if (!ownerReferences.isEmpty()) {
return Optional.of(fromOwnerReference(resource, ownerReferences.get(0), clusterScoped));
} else {
return Optional.empty();
}
}

public static ResourceID fromOwnerReference(HasMetadata resource, OwnerReference ownerReference,
boolean clusterScoped) {
return new ResourceID(ownerReference.getName(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,37 @@ public static <T extends HasMetadata> SecondaryToPrimaryMapper<T> fromLabel(
return fromMetadata(nameKey, namespaceKey, true);
}

public static <T extends HasMetadata> SecondaryToPrimaryMapper<T> fromOwnerReference() {
return fromOwnerReference(false);
public static <T extends HasMetadata> SecondaryToPrimaryMapper<T> fromOwnerReferences(
Class<? extends HasMetadata> primaryResourceType) {
return fromOwnerReferences(primaryResourceType, false);
}

/**
* @param clusterScope if the owner is a cluster scoped resource
* @return mapper
* @param <T> type of the secondary resource, where the owner reference is
*/
public static <T extends HasMetadata> SecondaryToPrimaryMapper<T> fromOwnerReference(
boolean clusterScope) {
return resource -> ResourceID.fromFirstOwnerReference(resource, clusterScope).map(Set::of)
.orElseGet(Collections::emptySet);
public static <T extends HasMetadata> SecondaryToPrimaryMapper<T> fromOwnerReferences(
Class<? extends HasMetadata> primaryResourceType, boolean clusterScoped) {
return fromOwnerReferences(HasMetadata.getApiVersion(primaryResourceType),
HasMetadata.getKind(primaryResourceType),
clusterScoped);
}

public static <T extends HasMetadata> SecondaryToPrimaryMapper<T> fromOwnerReferences(
HasMetadata primaryResource) {
return fromOwnerReferences(primaryResource, false);
}

public static <T extends HasMetadata> SecondaryToPrimaryMapper<T> fromOwnerReferences(
HasMetadata primaryResource,
boolean clusterScoped) {
return fromOwnerReferences(primaryResource.getApiVersion(), primaryResource.getKind(),
clusterScoped);
}

public static <T extends HasMetadata> SecondaryToPrimaryMapper<T> fromOwnerReferences(
String apiVersion, String kind,
boolean clusterScope) {
return resource -> resource.getMetadata().getOwnerReferences().stream()
return resource -> resource.getMetadata().getOwnerReferences()
.stream()
.filter(r -> r.getKind().equals(kind)
&& r.getApiVersion().equals(apiVersion))
.map(or -> ResourceID.fromOwnerReference(resource, or, clusterScope))
.collect(Collectors.toSet());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package io.javaoperatorsdk.operator.processing.event.source.informer;

import java.util.UUID;

import org.junit.jupiter.api.Test;

import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.javaoperatorsdk.operator.TestUtils;
import io.javaoperatorsdk.operator.processing.event.ResourceID;
import io.javaoperatorsdk.operator.sample.simple.TestCustomResource;
import io.javaoperatorsdk.operator.sample.simple.TestCustomResourceOtherV1;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;

class MappersTest {


@Test
void secondaryToPrimaryMapperFromOwnerReference() {
var primary = TestUtils.testCustomResource();
primary.getMetadata().setUid(UUID.randomUUID().toString());
var secondary = getConfigMap(primary);
secondary.addOwnerReference(primary);

var res = Mappers.fromOwnerReferences(TestCustomResource.class)
.toPrimaryResourceIDs(secondary);

assertThat(res).contains(ResourceID.fromResource(primary));
}

@Test
void secondaryToPrimaryMapperFromOwnerReferenceFiltersByType() {
var primary = TestUtils.testCustomResource();
primary.getMetadata().setUid(UUID.randomUUID().toString());
var secondary = getConfigMap(primary);
secondary.addOwnerReference(primary);

var res = Mappers.fromOwnerReferences(TestCustomResourceOtherV1.class)
.toPrimaryResourceIDs(secondary);

assertThat(res).isEmpty();
}


private static ConfigMap getConfigMap(TestCustomResource primary) {
return new ConfigMapBuilder()
.withMetadata(new ObjectMetaBuilder()
.withName("test1")
.withNamespace(primary.getMetadata().getNamespace())
.build())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

@Group("sample.javaoperatorsdk.io")
@Version("v1")
@Kind("TestCustomResource") // this is needed to override the automatically generated kind
@Kind("TestCustomResourceOtherV1") // this is needed to override the automatically generated kind
public class TestCustomResourceOtherV1
extends CustomResource<TestCustomResourceSpec, TestCustomResourceStatus> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ private static String getName(ConfigMap cm) {

@Override
public Set<ResourceID> toPrimaryResourceIDs(ConfigMap resource) {
return Mappers.fromOwnerReferences(false).toPrimaryResourceIDs(resource);
return Mappers.fromOwnerReferences(BulkDependentTestCustomResource.class, false)
.toPrimaryResourceIDs(resource);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ private ConfigMap desired(ClusterScopedCustomResource resource) {
public List<EventSource> prepareEventSources(
EventSourceContext<ClusterScopedCustomResource> context) {
var ies = new InformerEventSource<>(InformerConfiguration.from(ConfigMap.class, context)
.withSecondaryToPrimaryMapper(Mappers.fromOwnerReference(true))
.withSecondaryToPrimaryMapper(
Mappers.fromOwnerReferences(context.getPrimaryResourceClass(), true))
.withLabelSelector(TEST_LABEL_KEY + "=" + TEST_LABEL_VALUE)
.build(), context);
return List.of(ies);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ private ConfigMap createConfigMap(CreateUpdateEventFilterTestCustomResource reso
public List<EventSource> prepareEventSources(
EventSourceContext<CreateUpdateEventFilterTestCustomResource> context) {
InformerConfiguration<ConfigMap> informerConfiguration =
InformerConfiguration.from(ConfigMap.class)
InformerConfiguration.from(ConfigMap.class, context)
.withLabelSelector("integrationtest = " + this.getClass().getSimpleName())
.build();
final var informerEventSource =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public List<EventSource> prepareEventSources(
EventSourceContext<InformerEventSourceTestCustomResource> context) {

InformerConfiguration<ConfigMap> config =
InformerConfiguration.from(ConfigMap.class)
InformerConfiguration.from(ConfigMap.class, context)
.withSecondaryToPrimaryMapper(Mappers.fromAnnotation(RELATED_RESOURCE_NAME))
.build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public int getNumberOfExecutions() {
public List<EventSource> prepareEventSources(
EventSourceContext<MultipleSecondaryEventSourceCustomResource> context) {

var config = InformerConfiguration.from(ConfigMap.class)
var config = InformerConfiguration.from(ConfigMap.class, context)
.withNamespaces(context.getControllerConfiguration().getNamespaces())
.withLabelSelector("multisecondary")
.withSecondaryToPrimaryMapper(s -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public List<EventSource> prepareEventSources(
context.getPrimaryCache().addIndexer(CONFIG_MAP_RELATION_INDEXER, indexer);

var informerConfiguration =
InformerConfiguration.from(ConfigMap.class)
InformerConfiguration.from(ConfigMap.class, context)
.withSecondaryToPrimaryMapper(
(ConfigMap secondaryResource) -> context
.getPrimaryCache()
Expand Down
Loading