Skip to content

feat: Workflow extracted to a separate annotation #2274

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 2 commits into from
Mar 11, 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 @@ -11,13 +11,15 @@
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
import io.javaoperatorsdk.operator.api.reconciler.Workflow;
import io.javaoperatorsdk.operator.processing.event.source.EventSource;
import io.javaoperatorsdk.operator.processing.event.source.informer.InformerEventSource;

import java.util.Map;
import java.util.Optional;

@ControllerConfiguration(dependents = {@Dependent(type = ConfigMapDependentResource.class)})
@Workflow(dependents = {@Dependent(type = ConfigMapDependentResource.class)})
@ControllerConfiguration
public class {{artifactClassId}}Reconciler implements Reconciler<{{artifactClassId}}CustomResource> {

public UpdateControl<{{artifactClassId}}CustomResource> reconcile({{artifactClassId}}CustomResource primary,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
import io.javaoperatorsdk.operator.ReconcilerUtils;
import io.javaoperatorsdk.operator.api.config.Utils.Configurator;
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
import io.javaoperatorsdk.operator.api.config.workflow.WorkflowSpec;
import io.javaoperatorsdk.operator.api.reconciler.Constants;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
import io.javaoperatorsdk.operator.api.reconciler.Workflow;
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource;
import io.javaoperatorsdk.operator.processing.dependent.workflow.Condition;
Expand Down Expand Up @@ -97,6 +99,7 @@ public <R extends HasMetadata> ControllerConfiguration<R> getConfigurationFor(
protected <P extends HasMetadata> ControllerConfiguration<P> configFor(Reconciler<P> reconciler) {
final var annotation = reconciler.getClass().getAnnotation(
io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration.class);

if (annotation == null) {
throw new OperatorException(
"Missing mandatory @"
Expand Down Expand Up @@ -161,21 +164,26 @@ protected <P extends HasMetadata> ControllerConfiguration<P> configFor(Reconcile
Utils.instantiate(annotation.itemStore(), ItemStore.class, context), dependentFieldManager,
this, informerListLimit);

List<DependentResourceSpec> specs = dependentResources(annotation, config);
config.setDependentResources(specs);

final var workflowAnnotation = reconciler.getClass().getAnnotation(
io.javaoperatorsdk.operator.api.reconciler.Workflow.class);
if (workflowAnnotation != null) {
List<DependentResourceSpec> specs = dependentResources(workflowAnnotation, config);
WorkflowSpec workflowSpec = new WorkflowSpec(specs);
config.setWorkflowSpec(workflowSpec);
}

return config;
}

@SuppressWarnings({"unchecked", "rawtypes"})
private static List<DependentResourceSpec> dependentResources(
io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration annotation,
Workflow annotation,
ControllerConfiguration<?> parent) {
final var dependents =
valueOrDefault(annotation,
io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration::dependents,
new Dependent[] {});
if (dependents.length == 0) {
final var dependents = annotation.dependents();


if (dependents == null || dependents.length == 0) {
return Collections.emptyList();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
package io.javaoperatorsdk.operator.api.config;

import java.time.Duration;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.ReconcilerUtils;
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
import io.javaoperatorsdk.operator.api.config.workflow.WorkflowSpec;
import io.javaoperatorsdk.operator.api.reconciler.MaxReconciliationInterval;
import io.javaoperatorsdk.operator.processing.event.rate.LinearRateLimiter;
import io.javaoperatorsdk.operator.processing.event.rate.RateLimiter;
Expand Down Expand Up @@ -65,9 +63,8 @@ default RateLimiter getRateLimiter() {
return DEFAULT_RATE_LIMITER;
}

@SuppressWarnings("rawtypes")
default List<DependentResourceSpec> getDependentResources() {
return Collections.emptyList();
default Optional<WorkflowSpec> getWorkflowSpec() {
return Optional.empty();
}

default Optional<Duration> maxReconciliationInterval() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.client.informers.cache.ItemStore;
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
import io.javaoperatorsdk.operator.api.config.workflow.WorkflowSpec;
import io.javaoperatorsdk.operator.processing.event.rate.RateLimiter;
import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter;
import io.javaoperatorsdk.operator.processing.event.source.filter.OnAddFilter;
Expand Down Expand Up @@ -38,6 +39,7 @@ public class ControllerConfigurationOverrider<R extends HasMetadata> {
private String name;
private String fieldManager;
private Long informerListLimit;
private WorkflowSpec workflowSpec;

private ControllerConfigurationOverrider(ControllerConfiguration<R> original) {
this.finalizer = original.getFinalizerName();
Expand All @@ -55,6 +57,7 @@ private ControllerConfigurationOverrider(ControllerConfiguration<R> original) {
this.fieldManager = original.fieldManager();
this.informerListLimit = original.getInformerListLimit().orElse(null);
this.itemStore = original.getItemStore().orElse(null);
this.workflowSpec = original.getWorkflowSpec().orElse(null);
}

public ControllerConfigurationOverrider<R> withFinalizer(String finalizer) {
Expand Down Expand Up @@ -175,7 +178,7 @@ public ControllerConfigurationOverrider<R> withInformerListLimit(
public ControllerConfigurationOverrider<R> replacingNamedDependentResourceConfig(String name,
Object dependentResourceConfig) {

final var specs = original.getDependentResources();
final var specs = original.getWorkflowSpec().orElseThrow().getDependentResourceSpecs();
final var spec = specs.stream()
.filter(drs -> drs.getName().equals(name)).findFirst()
.orElseThrow(
Expand All @@ -193,9 +196,9 @@ public ControllerConfiguration<R> build() {
name,
generationAware, original.getAssociatedReconcilerClassName(), retry, rateLimiter,
reconciliationMaxInterval, onAddFilter, onUpdateFilter, genericFilter,
original.getDependentResources(),
namespaces, finalizer, labelSelector, configurations, itemStore, fieldManager,
original.getConfigurationService(), informerListLimit);
original.getConfigurationService(), informerListLimit,
original.getWorkflowSpec().orElse(null));
}

public static <R extends HasMetadata> ControllerConfigurationOverrider<R> override(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import io.fabric8.kubernetes.client.informers.cache.ItemStore;
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfigurationProvider;
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
import io.javaoperatorsdk.operator.api.config.workflow.WorkflowSpec;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
import io.javaoperatorsdk.operator.processing.event.rate.RateLimiter;
import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter;
Expand All @@ -32,20 +33,19 @@ public class ResolvedControllerConfiguration<P extends HasMetadata>
private final ItemStore<P> itemStore;
private final ConfigurationService configurationService;
private final String fieldManager;

private List<DependentResourceSpec> dependentResources;
private WorkflowSpec workflowSpec;

public ResolvedControllerConfiguration(Class<P> resourceClass, ControllerConfiguration<P> other) {
this(resourceClass, other.getName(), other.isGenerationAware(),
other.getAssociatedReconcilerClassName(), other.getRetry(), other.getRateLimiter(),
other.maxReconciliationInterval().orElse(null),
other.onAddFilter().orElse(null), other.onUpdateFilter().orElse(null),
other.genericFilter().orElse(null),
other.getDependentResources(), other.getNamespaces(),
other.getNamespaces(),
other.getFinalizerName(), other.getLabelSelector(), Collections.emptyMap(),
other.getItemStore().orElse(null), other.fieldManager(),
other.getConfigurationService(),
other.getInformerListLimit().orElse(null));
other.getInformerListLimit().orElse(null), other.getWorkflowSpec().orElse(null));
}

public static Duration getMaxReconciliationInterval(long interval, TimeUnit timeUnit) {
Expand All @@ -70,16 +70,16 @@ public ResolvedControllerConfiguration(Class<P> resourceClass, String name,
RateLimiter rateLimiter, Duration maxReconciliationInterval,
OnAddFilter<? super P> onAddFilter, OnUpdateFilter<? super P> onUpdateFilter,
GenericFilter<? super P> genericFilter,
List<DependentResourceSpec> dependentResources,
Set<String> namespaces, String finalizer, String labelSelector,
Map<DependentResourceSpec, Object> configurations, ItemStore<P> itemStore,
String fieldManager,
ConfigurationService configurationService, Long informerListLimit) {
ConfigurationService configurationService, Long informerListLimit,
WorkflowSpec workflowSpec) {
this(resourceClass, name, generationAware, associatedReconcilerClassName, retry, rateLimiter,
maxReconciliationInterval, onAddFilter, onUpdateFilter, genericFilter,
namespaces, finalizer, labelSelector, configurations, itemStore, fieldManager,
configurationService, informerListLimit);
setDependentResources(dependentResources);
setWorkflowSpec(workflowSpec);
}

protected ResolvedControllerConfiguration(Class<P> resourceClass, String name,
Expand All @@ -105,6 +105,7 @@ protected ResolvedControllerConfiguration(Class<P> resourceClass, String name,
this.finalizer =
ControllerConfiguration.ensureValidFinalizerName(finalizer, getResourceTypeName());
this.fieldManager = fieldManager;
this.workflowSpec = workflowSpec;
}

protected ResolvedControllerConfiguration(Class<P> resourceClass, String name,
Expand Down Expand Up @@ -144,14 +145,14 @@ public RateLimiter getRateLimiter() {
return rateLimiter;
}


@Override
public List<DependentResourceSpec> getDependentResources() {
return dependentResources;
public Optional<WorkflowSpec> getWorkflowSpec() {
return Optional.ofNullable(workflowSpec);
}

protected void setDependentResources(List<DependentResourceSpec> dependentResources) {
this.dependentResources = dependentResources == null ? Collections.emptyList()
: Collections.unmodifiableList(dependentResources);
public void setWorkflowSpec(WorkflowSpec workflowSpec) {
this.workflowSpec = workflowSpec;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.javaoperatorsdk.operator.api.config.workflow;

import java.util.List;

import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;

public class WorkflowSpec {

@SuppressWarnings("rawtypes")
private final List<DependentResourceSpec> dependentResourceSpecs;

public WorkflowSpec(List<DependentResourceSpec> dependentResourceSpecs) {
this.dependentResourceSpecs = dependentResourceSpecs;
}

public List<DependentResourceSpec> getDependentResourceSpecs() {
return dependentResourceSpecs;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.lang.annotation.Target;

import io.fabric8.kubernetes.client.informers.cache.ItemStore;
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
import io.javaoperatorsdk.operator.processing.event.rate.LinearRateLimiter;
import io.javaoperatorsdk.operator.processing.event.rate.RateLimiter;
import io.javaoperatorsdk.operator.processing.event.source.cache.BoundedItemStore;
Expand Down Expand Up @@ -93,15 +92,6 @@
MaxReconciliationInterval maxReconciliationInterval() default @MaxReconciliationInterval(
interval = MaxReconciliationInterval.DEFAULT_INTERVAL);


/**
* Optional list of {@link Dependent} configurations which associate a resource type to a
* {@link io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource} implementation
*
* @return the array of {@link Dependent} configurations
*/
Dependent[] dependents() default {};

/**
* Optional {@link Retry} implementation for the associated controller to use.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.javaoperatorsdk.operator.api.reconciler;

import java.lang.annotation.*;

import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Workflow {

Dependent[] dependents();

}
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package io.javaoperatorsdk.operator.processing.dependent.workflow;

import java.util.Optional;

import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
import io.javaoperatorsdk.operator.api.config.workflow.WorkflowSpec;

public interface ManagedWorkflowFactory<C extends ControllerConfiguration<?>> {

@SuppressWarnings({"rawtypes", "unchecked"})
ManagedWorkflowFactory DEFAULT = (configuration) -> {
final var dependentResourceSpecs = configuration.getDependentResources();
if (dependentResourceSpecs == null || dependentResourceSpecs.isEmpty()) {
final Optional<WorkflowSpec> workflowSpec = configuration.getWorkflowSpec();
if (workflowSpec.isEmpty()) {
return (ManagedWorkflow) (client, configuration1) -> new DefaultWorkflow(null);
}
ManagedWorkflowSupport support = new ManagedWorkflowSupport();
return support.createWorkflow(dependentResourceSpecs);
return support.createWorkflow(workflowSpec.orElseThrow());
};

@SuppressWarnings("rawtypes")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.javaoperatorsdk.operator.OperatorException;
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
import io.javaoperatorsdk.operator.api.config.workflow.WorkflowSpec;

@SuppressWarnings({"rawtypes", "unchecked"})
class ManagedWorkflowSupport {
Expand All @@ -38,10 +39,10 @@ public void checkForNameDuplication(List<DependentResourceSpec> dependentResourc
}
}


public <P extends HasMetadata> ManagedWorkflow<P> createWorkflow(
List<DependentResourceSpec> dependentResourceSpecs) {
return createAsDefault(dependentResourceSpecs);
WorkflowSpec workflowSpec) {

return createAsDefault(workflowSpec.getDependentResourceSpecs());
}

<P extends HasMetadata> DefaultManagedWorkflow<P> createAsDefault(
Expand Down
Loading