Skip to content

refactor: isolate index handling to BulkDependentResource interface #1504

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

Closed
wants to merge 48 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
a488572
feat: decouple event source from cache + list discriminator (#1378)
csviri Sep 28, 2022
b156a56
feat: improvements on caching and dependent resources
csviri Jul 27, 2022
e20f185
wip
csviri Jul 27, 2022
9103864
kubernetes dependent resource configuration
csviri Jul 28, 2022
0741846
IT fix
csviri Jul 28, 2022
2758551
fixed ITs
csviri Jul 29, 2022
50bd916
index based discriminator
csviri Jul 29, 2022
97ce295
IT fix
csviri Jul 29, 2022
0718875
wip
csviri Jul 29, 2022
b71c7c9
fixes from rebase from next
csviri Aug 26, 2022
6337e44
fix after rebase
csviri Sep 5, 2022
01c33ec
event source provider to context
csviri Sep 6, 2022
b701eb6
todo fixes
csviri Sep 16, 2022
562f7d2
remove void discriminator
csviri Sep 27, 2022
b414d58
fix: bulk creation of dependent resource directly in abstract resource
csviri Sep 8, 2022
3b34d1e
wip
csviri Sep 9, 2022
c7f3671
wip
csviri Sep 9, 2022
759b2e1
wip to start IT
csviri Sep 9, 2022
1b7e714
fixes, progress
csviri Sep 9, 2022
953d274
wp
csviri Sep 12, 2022
98da2e1
matcher
csviri Sep 12, 2022
40c3e47
test passes
csviri Sep 12, 2022
ceca37c
bulk dependent resource to an interface
csviri Sep 13, 2022
abccb4e
wip
csviri Sep 14, 2022
1fe3486
test improvement
csviri Sep 14, 2022
83224c8
note
csviri Sep 14, 2022
2d627f7
wip
csviri Sep 15, 2022
580c62f
rebase on next
csviri Sep 20, 2022
5339b04
increates test timeout
csviri Sep 20, 2022
9d17aba
comment
csviri Sep 20, 2022
1704be9
fix format
csviri Sep 20, 2022
fed173d
wip
csviri Sep 20, 2022
c7db869
delete, other improvements
csviri Sep 21, 2022
da8541e
manage tests, refactored ITs
csviri Sep 21, 2022
714f42c
additionl IT
csviri Sep 21, 2022
57428da
external resource
csviri Sep 21, 2022
13ff73e
external resource IT
csviri Sep 22, 2022
6984571
docs
csviri Sep 22, 2022
d5e814d
refactor: clean-up
metacosm Sep 27, 2022
4e44a50
refactor: make ReconcileResult immutable
metacosm Sep 27, 2022
408fc9c
fix: do not create map if resource is null
metacosm Sep 27, 2022
cabe07d
fix: make things work again after rebase
metacosm Sep 28, 2022
72ebce3
refactor: simplify by removing discriminator factory
metacosm Sep 28, 2022
b5f982f
fix: properly use indexed version
metacosm Sep 28, 2022
da8163b
revert strange comment
csviri Sep 29, 2022
1d303a0
fix: make it clearer when CRD file isn't found
metacosm Aug 29, 2022
214c636
refactor: isolate index handling to BulkDependentResource interface
metacosm Sep 29, 2022
e43cb86
fix: only apply CRD when there is a CRD to apply
metacosm Sep 29, 2022
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 @@ -17,9 +17,8 @@
import io.javaoperatorsdk.operator.OperatorException;
import io.javaoperatorsdk.operator.ReconcilerUtils;
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
import io.javaoperatorsdk.operator.api.reconciler.Constants;
import io.javaoperatorsdk.operator.api.reconciler.*;
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
Expand Down Expand Up @@ -54,9 +53,8 @@ public AnnotationControllerConfiguration(Reconciler<P> reconciler) {
this.reconciler = reconciler;
this.annotation = reconciler.getClass().getAnnotation(ControllerConfiguration.class);
if (annotation == null) {
throw new OperatorException(
"Missing mandatory @" + ControllerConfiguration.class.getSimpleName() +
" annotation for reconciler: " + reconciler);
throw new OperatorException("Missing mandatory @" + CONTROLLER_CONFIG_ANNOTATION +
" annotation for reconciler: " + reconciler);
}
}

Expand Down Expand Up @@ -247,9 +245,9 @@ public List<DependentResourceSpec> getDependentResources() {
final var context = "DependentResource of type '" + dependentType.getName() + "'";
spec = new DependentResourceSpec(dependentType, config, name,
Set.of(dependent.dependsOn()),
instantiateConditionIfNotDefault(dependent.readyPostcondition(), context),
instantiateConditionIfNotDefault(dependent.reconcilePrecondition(), context),
instantiateConditionIfNotDefault(dependent.deletePostcondition(), context));
instantiateIfNotDefault(dependent.readyPostcondition(), Condition.class, context),
instantiateIfNotDefault(dependent.reconcilePrecondition(), Condition.class, context),
instantiateIfNotDefault(dependent.deletePostcondition(), Condition.class, context));
specsMap.put(name, spec);
}

Expand All @@ -258,10 +256,10 @@ public List<DependentResourceSpec> getDependentResources() {
return specs;
}

protected Condition<?, ?> instantiateConditionIfNotDefault(Class<? extends Condition> condition,
protected <T> T instantiateIfNotDefault(Class<? extends T> toInstantiate, Class<T> defaultClass,
String context) {
if (condition != Condition.class) {
return instantiateAndConfigureIfNeeded(condition, Condition.class, context);
if (!defaultClass.equals(toInstantiate)) {
return instantiateAndConfigureIfNeeded(toInstantiate, defaultClass, context);
}
return null;
}
Expand All @@ -287,6 +285,7 @@ private Object createKubernetesResourceConfig(Class<? extends DependentResource>
OnUpdateFilter<? extends HasMetadata> onUpdateFilter = null;
OnDeleteFilter<? extends HasMetadata> onDeleteFilter = null;
GenericFilter<? extends HasMetadata> genericFilter = null;
ResourceDiscriminator<?, ? extends HasMetadata> resourceDiscriminator = null;
if (kubeDependent != null) {
if (!Arrays.equals(KubernetesDependent.DEFAULT_NAMESPACES,
kubeDependent.namespaces())) {
Expand All @@ -297,7 +296,6 @@ private Object createKubernetesResourceConfig(Class<? extends DependentResource>
final var fromAnnotation = kubeDependent.labelSelector();
labelSelector = Constants.NO_VALUE_SET.equals(fromAnnotation) ? null : fromAnnotation;


final var context =
KUBE_DEPENDENT_NAME + " annotation on " + dependentType.getName() + " DependentResource";
onAddFilter = createFilter(kubeDependent.onAddFilter(), OnAddFilter.class, context)
Expand All @@ -311,10 +309,15 @@ private Object createKubernetesResourceConfig(Class<? extends DependentResource>
genericFilter =
createFilter(kubeDependent.genericFilter(), GenericFilter.class, context)
.orElse(null);

resourceDiscriminator =
instantiateIfNotDefault(kubeDependent.resourceDiscriminator(),
ResourceDiscriminator.class, context);
}

config =
new KubernetesDependentResourceConfig(namespaces, labelSelector, configuredNS, onAddFilter,
new KubernetesDependentResourceConfig(namespaces, labelSelector, configuredNS,
resourceDiscriminator, onAddFilter,
onUpdateFilter, onDeleteFilter, genericFilter);

return config;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,27 @@
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.event.EventSourceRetriever;

public interface Context<P extends HasMetadata> {

Optional<RetryInfo> getRetryInfo();

default <T> Optional<T> getSecondaryResource(Class<T> expectedType) {
return getSecondaryResource(expectedType, null);
default <R> Optional<R> getSecondaryResource(Class<R> expectedType) {
return getSecondaryResource(expectedType, (String) null);
}

<T> Set<T> getSecondaryResources(Class<T> expectedType);
<R> Set<R> getSecondaryResources(Class<R> expectedType);

<T> Optional<T> getSecondaryResource(Class<T> expectedType, String eventSourceName);
@Deprecated(forRemoval = true)
<R> Optional<R> getSecondaryResource(Class<R> expectedType, String eventSourceName);

<R> Optional<R> getSecondaryResource(Class<R> expectedType,
ResourceDiscriminator<R, P> discriminator);

ControllerConfiguration<P> getControllerConfiguration();

ManagedDependentResourceContext managedDependentResourceContext();

EventSourceRetriever<P> eventSourceRetriever();
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.DefaultManagedDependentResourceContext;
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedDependentResourceContext;
import io.javaoperatorsdk.operator.processing.Controller;
import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever;

public class DefaultContext<P extends HasMetadata> implements Context<P> {

Expand Down Expand Up @@ -47,6 +48,12 @@ public <T> Optional<T> getSecondaryResource(Class<T> expectedType, String eventS
.getSecondaryResource(primaryResource);
}

@Override
public <R> Optional<R> getSecondaryResource(Class<R> expectedType,
ResourceDiscriminator<R, P> discriminator) {
return discriminator.distinguish(expectedType, primaryResource, this);
}

@Override
public ControllerConfiguration<P> getControllerConfiguration() {
return controllerConfiguration;
Expand All @@ -57,6 +64,11 @@ public ManagedDependentResourceContext managedDependentResourceContext() {
return defaultManagedDependentResourceContext;
}

@Override
public EventSourceRetriever<P> eventSourceRetriever() {
return controller.getEventSourceManager();
}

public DefaultContext<P> setRetryInfo(RetryInfo retryInfo) {
this.retryInfo = retryInfo;
return this;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.javaoperatorsdk.operator.api.reconciler;

import java.util.Optional;

import io.fabric8.kubernetes.api.model.HasMetadata;

public interface ResourceDiscriminator<R, P extends HasMetadata> {

Optional<R> distinguish(Class<R> resource, P primary, Context<P> context);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package io.javaoperatorsdk.operator.api.reconciler;

import java.util.Optional;
import java.util.function.Function;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.processing.event.ResourceID;

public class ResourceIDMatcherDiscriminator<R extends HasMetadata, P extends HasMetadata>
implements ResourceDiscriminator<R, P> {

private final Function<P, ResourceID> mapper;

public ResourceIDMatcherDiscriminator(Function<P, ResourceID> mapper) {
this.mapper = mapper;
}

@Override
public Optional<R> distinguish(Class<R> resource, P primary, Context<P> context) {
var resourceID = mapper.apply(primary);
return context.getSecondaryResources(resource).stream()
.filter(resourceID::isSameResource)
.findFirst();
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
package io.javaoperatorsdk.operator.api.reconciler.dependent;

import java.util.Optional;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.processing.ResourceOwner;

/**
* An interface to implement and provide dependent resource support.
*
* @param <R> the dependent resource type
* @param <P> the associated primary resource type
*/
public interface DependentResource<R, P extends HasMetadata> extends ResourceOwner<R, P> {
public interface DependentResource<R, P extends HasMetadata> {

/**
* Reconciles the dependent resource given the desired primary state
Expand All @@ -21,6 +22,17 @@ public interface DependentResource<R, P extends HasMetadata> extends ResourceOwn
*/
ReconcileResult<R> reconcile(P primary, Context<P> context);

/**
* Retrieves the resource type associated with this DependentResource
*
* @return the resource type associated with this DependentResource
*/
Class<R> resourceType();

default Optional<R> getSecondaryResource(P primary, Context<P> context) {
return Optional.empty();
}

/**
* Computes a default name for the specified DependentResource class
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package io.javaoperatorsdk.operator.api.reconciler.dependent;

import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.processing.event.ResourceID;

public class ReconcileResult<R> {

private final R resource;
private final Operation operation;
private final Map<R, Operation> resourceOperations;

public static <T> ReconcileResult<T> resourceCreated(T resource) {
return new ReconcileResult<>(resource, Operation.CREATED);
Expand All @@ -22,25 +22,49 @@ public static <T> ReconcileResult<T> noOperation(T resource) {
return new ReconcileResult<>(resource, Operation.NONE);
}

@SafeVarargs
public static <T> ReconcileResult<T> aggregatedResult(ReconcileResult<T>... results) {
if (results == null) {
throw new IllegalArgumentException("Should provide results to aggregate");
}
if (results.length == 1) {
return results[0];
}
final Map<T, Operation> operations = new HashMap<>(results.length);
for (ReconcileResult<T> res : results) {
res.getSingleResource().ifPresent(r -> operations.put(r, res.getSingleOperation()));
}
return new ReconcileResult<>(operations);
}

@Override
public String toString() {
return getResource()
.map(r -> r instanceof HasMetadata ? ResourceID.fromResource((HasMetadata) r) : r)
.orElse("no resource")
+ " -> " + operation;
return resourceOperations.entrySet().stream().collect(Collectors.toMap(
e -> e instanceof HasMetadata ? ResourceID.fromResource((HasMetadata) e) : e,
Map.Entry::getValue))
.toString();
}

private ReconcileResult(R resource, Operation operation) {
this.resource = resource;
this.operation = operation;
resourceOperations = resource != null ? Map.of(resource, operation) : Collections.emptyMap();
}

private ReconcileResult(Map<R, Operation> operations) {
resourceOperations = Collections.unmodifiableMap(operations);
}

public Optional<R> getSingleResource() {
return resourceOperations.entrySet().stream().findFirst().map(Map.Entry::getKey);
}

public Optional<R> getResource() {
return Optional.ofNullable(resource);
public Operation getSingleOperation() {
return resourceOperations.entrySet().stream().findFirst().map(Map.Entry::getValue)
.orElseThrow();
}

public Operation getOperation() {
return operation;
@SuppressWarnings("unused")
public Map<R, Operation> getResourceOperations() {
return resourceOperations;
}

public enum Operation {
Expand Down

This file was deleted.

Loading