Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c0d687b

Browse files
committedAug 8, 2024
feat: explicit workflow invocation (#2289)
Signed-off-by: Attila Mészáros <csviri@gmail.com>
1 parent 6e4cf34 commit c0d687b

23 files changed

+456
-33
lines changed
 

Diff for: ‎docs/documentation/v5-0-migration.md

+2
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ permalink: /docs/v5-0-migration
1717
[`EventSourceUtils`](https://github.com/operator-framework/java-operator-sdk/blob/main/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/EventSourceUtils.java#L11-L11)
1818
now contains all the utility methods used for event sources naming that were previously defined in
1919
the `EventSourceInitializer` interface.
20+
3. `ManagedDependentResourceContext` has been renamed to `ManagedWorkflowAndDependentResourceContext` and is accessed
21+
via the accordingly renamed `managedWorkflowAndDependentResourceContext` method.

Diff for: ‎operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/BaseConfigurationService.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ protected <P extends HasMetadata> ControllerConfiguration<P> configFor(Reconcile
169169
io.javaoperatorsdk.operator.api.reconciler.Workflow.class);
170170
if (workflowAnnotation != null) {
171171
List<DependentResourceSpec> specs = dependentResources(workflowAnnotation, config);
172-
WorkflowSpec workflowSpec = new WorkflowSpec(specs);
172+
WorkflowSpec workflowSpec = new WorkflowSpec(specs, workflowAnnotation.explicitInvocation());
173173
config.setWorkflowSpec(workflowSpec);
174174
}
175175

Diff for: ‎operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/workflow/WorkflowSpec.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,19 @@ public class WorkflowSpec {
88

99
@SuppressWarnings("rawtypes")
1010
private final List<DependentResourceSpec> dependentResourceSpecs;
11+
private final boolean explicitInvocation;
1112

12-
public WorkflowSpec(List<DependentResourceSpec> dependentResourceSpecs) {
13+
public WorkflowSpec(List<DependentResourceSpec> dependentResourceSpecs,
14+
boolean explicitInvocation) {
1315
this.dependentResourceSpecs = dependentResourceSpecs;
16+
this.explicitInvocation = explicitInvocation;
1417
}
1518

1619
public List<DependentResourceSpec> getDependentResourceSpecs() {
1720
return dependentResourceSpecs;
1821
}
22+
23+
public boolean isExplicitInvocation() {
24+
return explicitInvocation;
25+
}
1926
}

Diff for: ‎operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import io.fabric8.kubernetes.api.model.HasMetadata;
99
import io.fabric8.kubernetes.client.KubernetesClient;
1010
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
11-
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedDependentResourceContext;
11+
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedWorkflowAndDependentResourceContext;
1212
import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever;
1313
import io.javaoperatorsdk.operator.processing.event.source.IndexerResourceCache;
1414

@@ -34,7 +34,14 @@ <R> Optional<R> getSecondaryResource(Class<R> expectedType,
3434

3535
ControllerConfiguration<P> getControllerConfiguration();
3636

37-
ManagedDependentResourceContext managedDependentResourceContext();
37+
/**
38+
* Retrieve the {@link ManagedWorkflowAndDependentResourceContext} used to interact with
39+
* {@link io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResource}s and associated
40+
* {@link io.javaoperatorsdk.operator.processing.dependent.workflow.Workflow}
41+
*
42+
* @return the {@link ManagedWorkflowAndDependentResourceContext}
43+
*/
44+
ManagedWorkflowAndDependentResourceContext managedWorkflowAndDependentResourceContext();
3845

3946
EventSourceRetriever<P> eventSourceRetriever();
4047

Diff for: ‎operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/DefaultContext.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
import io.fabric8.kubernetes.api.model.HasMetadata;
1010
import io.fabric8.kubernetes.client.KubernetesClient;
1111
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
12-
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.DefaultManagedDependentResourceContext;
13-
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedDependentResourceContext;
12+
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.DefaultManagedWorkflowAndDependentResourceContext;
13+
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.ManagedWorkflowAndDependentResourceContext;
1414
import io.javaoperatorsdk.operator.processing.Controller;
1515
import io.javaoperatorsdk.operator.processing.event.EventSourceRetriever;
1616
import io.javaoperatorsdk.operator.processing.event.ResourceID;
@@ -21,14 +21,15 @@ public class DefaultContext<P extends HasMetadata> implements Context<P> {
2121
private final Controller<P> controller;
2222
private final P primaryResource;
2323
private final ControllerConfiguration<P> controllerConfiguration;
24-
private final DefaultManagedDependentResourceContext defaultManagedDependentResourceContext;
24+
private final DefaultManagedWorkflowAndDependentResourceContext<P> defaultManagedDependentResourceContext;
2525

2626
public DefaultContext(RetryInfo retryInfo, Controller<P> controller, P primaryResource) {
2727
this.retryInfo = retryInfo;
2828
this.controller = controller;
2929
this.primaryResource = primaryResource;
3030
this.controllerConfiguration = controller.getConfiguration();
31-
this.defaultManagedDependentResourceContext = new DefaultManagedDependentResourceContext();
31+
this.defaultManagedDependentResourceContext =
32+
new DefaultManagedWorkflowAndDependentResourceContext<>(controller, primaryResource, this);
3233
}
3334

3435
@Override
@@ -79,7 +80,7 @@ public ControllerConfiguration<P> getControllerConfiguration() {
7980
}
8081

8182
@Override
82-
public ManagedDependentResourceContext managedDependentResourceContext() {
83+
public ManagedWorkflowAndDependentResourceContext managedWorkflowAndDependentResourceContext() {
8384
return defaultManagedDependentResourceContext;
8485
}
8586

Diff for: ‎operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Workflow.java

+8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.lang.annotation.*;
44

5+
import io.fabric8.kubernetes.api.model.HasMetadata;
56
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
67

78
@Inherited
@@ -11,4 +12,11 @@
1112

1213
Dependent[] dependents();
1314

15+
/**
16+
* If true, managed workflow should be explicitly invoked within the reconciler implementation. If
17+
* false workflow is invoked just before the {@link Reconciler#reconcile(HasMetadata, Context)}
18+
* method.
19+
*/
20+
boolean explicitInvocation() default false;
21+
1422
}
+36-4
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,30 @@
33
import java.util.Optional;
44
import java.util.concurrent.ConcurrentHashMap;
55

6+
import io.fabric8.kubernetes.api.model.HasMetadata;
7+
import io.javaoperatorsdk.operator.api.reconciler.Context;
8+
import io.javaoperatorsdk.operator.processing.Controller;
69
import io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowCleanupResult;
710
import io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowReconcileResult;
811

912
@SuppressWarnings("rawtypes")
10-
public class DefaultManagedDependentResourceContext implements ManagedDependentResourceContext {
13+
public class DefaultManagedWorkflowAndDependentResourceContext<P extends HasMetadata>
14+
implements ManagedWorkflowAndDependentResourceContext {
1115

16+
private final ConcurrentHashMap attributes = new ConcurrentHashMap();
17+
private final Controller<P> controller;
18+
private final P primaryResource;
19+
private final Context<P> context;
1220
private WorkflowReconcileResult workflowReconcileResult;
1321
private WorkflowCleanupResult workflowCleanupResult;
14-
private final ConcurrentHashMap attributes = new ConcurrentHashMap();
22+
23+
public DefaultManagedWorkflowAndDependentResourceContext(Controller<P> controller,
24+
P primaryResource,
25+
Context<P> context) {
26+
this.controller = controller;
27+
this.primaryResource = primaryResource;
28+
this.context = context;
29+
}
1530

1631
@Override
1732
public <T> Optional<T> get(Object key, Class<T> expectedType) {
@@ -37,13 +52,13 @@ public <T> T getMandatory(Object key, Class<T> expectedType) {
3752
+ ") is missing or not of the expected type"));
3853
}
3954

40-
public DefaultManagedDependentResourceContext setWorkflowExecutionResult(
55+
public DefaultManagedWorkflowAndDependentResourceContext setWorkflowExecutionResult(
4156
WorkflowReconcileResult workflowReconcileResult) {
4257
this.workflowReconcileResult = workflowReconcileResult;
4358
return this;
4459
}
4560

46-
public DefaultManagedDependentResourceContext setWorkflowCleanupResult(
61+
public DefaultManagedWorkflowAndDependentResourceContext setWorkflowCleanupResult(
4762
WorkflowCleanupResult workflowCleanupResult) {
4863
this.workflowCleanupResult = workflowCleanupResult;
4964
return this;
@@ -58,4 +73,21 @@ public WorkflowReconcileResult getWorkflowReconcileResult() {
5873
public WorkflowCleanupResult getWorkflowCleanupResult() {
5974
return workflowCleanupResult;
6075
}
76+
77+
@Override
78+
public void reconcileManagedWorkflow() {
79+
if (!controller.isWorkflowExplicitInvocation()) {
80+
throw new IllegalStateException("Workflow explicit invocation is not set.");
81+
}
82+
controller.reconcileManagedWorkflow(primaryResource, context);
83+
}
84+
85+
@Override
86+
public void cleanupManageWorkflow() {
87+
if (!controller.isWorkflowExplicitInvocation()) {
88+
throw new IllegalStateException("Workflow explicit invocation is not set.");
89+
}
90+
controller.cleanupManagedWorkflow(primaryResource, context);
91+
}
92+
6193
}

Diff for: ‎operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/ManagedDependentResourceContext.java renamed to ‎operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/dependent/managed/ManagedWorkflowAndDependentResourceContext.java

+21-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* Contextual information related to {@link DependentResource} either to retrieve the actual
1111
* implementations to interact with them or to pass information between them and/or the reconciler
1212
*/
13-
public interface ManagedDependentResourceContext {
13+
public interface ManagedWorkflowAndDependentResourceContext {
1414

1515
/**
1616
* Retrieve a contextual object, if it exists and is of the specified expected type, associated
@@ -37,7 +37,6 @@ public interface ManagedDependentResourceContext {
3737
* @return an Optional containing the previous value associated with the key or
3838
* {@link Optional#empty()} if none existed
3939
*/
40-
@SuppressWarnings("unchecked")
4140
<T> T put(Object key, T value);
4241

4342
/**
@@ -54,5 +53,25 @@ public interface ManagedDependentResourceContext {
5453

5554
WorkflowReconcileResult getWorkflowReconcileResult();
5655

56+
@SuppressWarnings("unused")
5757
WorkflowCleanupResult getWorkflowCleanupResult();
58+
59+
/**
60+
* Explicitly reconcile the declared workflow for the associated
61+
* {@link io.javaoperatorsdk.operator.api.reconciler.Reconciler}
62+
*
63+
* @throws IllegalStateException if called when explicit invocation is not requested
64+
*/
65+
void reconcileManagedWorkflow();
66+
67+
/**
68+
* Explicitly clean-up dependent resources in the declared workflow for the associated
69+
* {@link io.javaoperatorsdk.operator.api.reconciler.Reconciler}. Note that calling this method is
70+
* only needed if the associated reconciler implements the
71+
* {@link io.javaoperatorsdk.operator.api.reconciler.Cleaner} interface.
72+
*
73+
* @throws IllegalStateException if called when explicit invocation is not requested
74+
*/
75+
void cleanupManageWorkflow();
76+
5877
}

Diff for: ‎operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java

+56-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package io.javaoperatorsdk.operator.processing;
22

3-
import java.util.*;
3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
import java.util.Optional;
8+
import java.util.Set;
49

510
import org.slf4j.Logger;
611
import org.slf4j.LoggerFactory;
@@ -18,13 +23,22 @@
1823
import io.javaoperatorsdk.operator.RegisteredController;
1924
import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
2025
import io.javaoperatorsdk.operator.api.config.ExecutorServiceManager;
26+
import io.javaoperatorsdk.operator.api.config.workflow.WorkflowSpec;
2127
import io.javaoperatorsdk.operator.api.monitoring.Metrics;
2228
import io.javaoperatorsdk.operator.api.monitoring.Metrics.ControllerExecution;
23-
import io.javaoperatorsdk.operator.api.reconciler.*;
29+
import io.javaoperatorsdk.operator.api.reconciler.Cleaner;
30+
import io.javaoperatorsdk.operator.api.reconciler.Constants;
31+
import io.javaoperatorsdk.operator.api.reconciler.Context;
32+
import io.javaoperatorsdk.operator.api.reconciler.ContextInitializer;
33+
import io.javaoperatorsdk.operator.api.reconciler.DeleteControl;
34+
import io.javaoperatorsdk.operator.api.reconciler.EventSourceContext;
35+
import io.javaoperatorsdk.operator.api.reconciler.Ignore;
36+
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
37+
import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
2438
import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceNotFoundException;
2539
import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceProvider;
2640
import io.javaoperatorsdk.operator.api.reconciler.dependent.EventSourceReferencer;
27-
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.DefaultManagedDependentResourceContext;
41+
import io.javaoperatorsdk.operator.api.reconciler.dependent.managed.DefaultManagedWorkflowAndDependentResourceContext;
2842
import io.javaoperatorsdk.operator.health.ControllerHealthInfo;
2943
import io.javaoperatorsdk.operator.processing.dependent.workflow.Workflow;
3044
import io.javaoperatorsdk.operator.processing.dependent.workflow.WorkflowCleanupResult;
@@ -130,12 +144,11 @@ public Map<String, Object> metadata() {
130144
@Override
131145
public UpdateControl<P> execute() throws Exception {
132146
initContextIfNeeded(resource, context);
133-
if (!managedWorkflow.isEmpty()) {
134-
var res = managedWorkflow.reconcile(resource, context);
135-
((DefaultManagedDependentResourceContext) context.managedDependentResourceContext())
136-
.setWorkflowExecutionResult(res);
137-
res.throwAggregateExceptionIfErrorsPresent();
138-
}
147+
configuration.getWorkflowSpec().ifPresent(ws -> {
148+
if (!isWorkflowExplicitInvocation()) {
149+
reconcileManagedWorkflow(resource, context);
150+
}
151+
});
139152
return reconciler.reconcile(resource, context);
140153
}
141154
});
@@ -175,12 +188,13 @@ public Map<String, Object> metadata() {
175188
public DeleteControl execute() {
176189
initContextIfNeeded(resource, context);
177190
WorkflowCleanupResult workflowCleanupResult = null;
178-
if (managedWorkflow.hasCleaner()) {
179-
workflowCleanupResult = managedWorkflow.cleanup(resource, context);
180-
((DefaultManagedDependentResourceContext) context.managedDependentResourceContext())
181-
.setWorkflowCleanupResult(workflowCleanupResult);
182-
workflowCleanupResult.throwAggregateExceptionIfErrorsPresent();
191+
192+
// The cleanup is called also when explicit invocation is true, but the cleaner is not
193+
// implemented
194+
if (!isCleaner || !isWorkflowExplicitInvocation()) {
195+
workflowCleanupResult = cleanupManagedWorkflow(resource, context);
183196
}
197+
184198
if (isCleaner) {
185199
var cleanupResult = ((Cleaner<P>) reconciler).cleanup(resource, context);
186200
if (!cleanupResult.isRemoveFinalizer()) {
@@ -437,4 +451,32 @@ public ExecutorServiceManager getExecutorServiceManager() {
437451
public EventSourceContext<P> eventSourceContext() {
438452
return eventSourceContext;
439453
}
454+
455+
public void reconcileManagedWorkflow(P primary, Context<P> context) {
456+
if (!managedWorkflow.isEmpty()) {
457+
var res = managedWorkflow.reconcile(primary, context);
458+
((DefaultManagedWorkflowAndDependentResourceContext) context
459+
.managedWorkflowAndDependentResourceContext())
460+
.setWorkflowExecutionResult(res);
461+
res.throwAggregateExceptionIfErrorsPresent();
462+
}
463+
}
464+
465+
public WorkflowCleanupResult cleanupManagedWorkflow(P resource, Context<P> context) {
466+
if (managedWorkflow.hasCleaner()) {
467+
var workflowCleanupResult = managedWorkflow.cleanup(resource, context);
468+
((DefaultManagedWorkflowAndDependentResourceContext) context
469+
.managedWorkflowAndDependentResourceContext())
470+
.setWorkflowCleanupResult(workflowCleanupResult);
471+
workflowCleanupResult.throwAggregateExceptionIfErrorsPresent();
472+
return workflowCleanupResult;
473+
} else {
474+
return null;
475+
}
476+
}
477+
478+
public boolean isWorkflowExplicitInvocation() {
479+
return configuration.getWorkflowSpec().map(WorkflowSpec::isExplicitInvocation)
480+
.orElse(false);
481+
}
440482
}

Diff for: ‎operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/dependent/workflow/ManagedWorkflowTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ ManagedWorkflow managedWorkflow(DependentResourceSpec... specs) {
6464
final var configuration = mock(ControllerConfiguration.class);
6565
final var specList = List.of(specs);
6666

67-
var ws = new WorkflowSpec(specList);
67+
var ws = new WorkflowSpec(specList, false);
6868
when(configuration.getWorkflowSpec()).thenReturn(Optional.of(ws));
6969

7070
return new BaseConfigurationService().getWorkflowFactory()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package io.javaoperatorsdk.operator;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.junit.jupiter.api.extension.RegisterExtension;
5+
6+
import io.fabric8.kubernetes.api.model.ConfigMap;
7+
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
8+
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
9+
import io.javaoperatorsdk.operator.sample.workflowexplicitcleanup.WorkflowExplicitCleanupCustomResource;
10+
import io.javaoperatorsdk.operator.sample.workflowexplicitcleanup.WorkflowExplicitCleanupReconciler;
11+
12+
import static org.assertj.core.api.Assertions.assertThat;
13+
import static org.awaitility.Awaitility.await;
14+
15+
public class WorkflowExplicitCleanupIT {
16+
17+
public static final String RESOURCE_NAME = "test1";
18+
19+
@RegisterExtension
20+
LocallyRunOperatorExtension extension =
21+
LocallyRunOperatorExtension.builder()
22+
.withReconciler(WorkflowExplicitCleanupReconciler.class)
23+
.build();
24+
25+
@Test
26+
void workflowInvokedExplicitly() {
27+
var res = extension.create(testResource());
28+
29+
await().untilAsserted(() -> {
30+
assertThat(extension.get(ConfigMap.class, RESOURCE_NAME)).isNotNull();
31+
});
32+
33+
extension.delete(res);
34+
35+
// The ConfigMap is not garbage collected, this tests that even if the cleaner is not
36+
// implemented the workflow cleanup still called even if there is explicit invocation
37+
await().untilAsserted(() -> {
38+
assertThat(extension.get(ConfigMap.class, RESOURCE_NAME)).isNull();
39+
});
40+
}
41+
42+
WorkflowExplicitCleanupCustomResource testResource() {
43+
var res = new WorkflowExplicitCleanupCustomResource();
44+
res.setMetadata(new ObjectMetaBuilder()
45+
.withName(RESOURCE_NAME)
46+
.build());
47+
return res;
48+
}
49+
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package io.javaoperatorsdk.operator;
2+
3+
import org.junit.jupiter.api.Test;
4+
import org.junit.jupiter.api.extension.RegisterExtension;
5+
6+
import io.fabric8.kubernetes.api.model.ConfigMap;
7+
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
8+
import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
9+
import io.javaoperatorsdk.operator.sample.workflowexplicitinvocation.WorkflowExplicitInvocationCustomResource;
10+
import io.javaoperatorsdk.operator.sample.workflowexplicitinvocation.WorkflowExplicitInvocationReconciler;
11+
import io.javaoperatorsdk.operator.sample.workflowexplicitinvocation.WorkflowExplicitInvocationSpec;
12+
13+
import static org.assertj.core.api.Assertions.assertThat;
14+
import static org.awaitility.Awaitility.await;
15+
16+
public class WorkflowExplicitInvocationIT {
17+
18+
public static final String RESOURCE_NAME = "test1";
19+
20+
@RegisterExtension
21+
LocallyRunOperatorExtension extension =
22+
LocallyRunOperatorExtension.builder()
23+
.withReconciler(WorkflowExplicitInvocationReconciler.class)
24+
.build();
25+
26+
@Test
27+
void workflowInvokedExplicitly() {
28+
var res = extension.create(testResource());
29+
var reconciler = extension.getReconcilerOfType(WorkflowExplicitInvocationReconciler.class);
30+
31+
await().untilAsserted(() -> {
32+
assertThat(reconciler.getNumberOfExecutions()).isEqualTo(1);
33+
assertThat(extension.get(ConfigMap.class, RESOURCE_NAME)).isNull();
34+
});
35+
36+
reconciler.setInvokeWorkflow(true);
37+
38+
// trigger reconciliation
39+
res.getSpec().setValue("changed value");
40+
res = extension.replace(res);
41+
42+
await().untilAsserted(() -> {
43+
assertThat(reconciler.getNumberOfExecutions()).isEqualTo(2);
44+
assertThat(extension.get(ConfigMap.class, RESOURCE_NAME)).isNotNull();
45+
});
46+
47+
extension.delete(res);
48+
49+
// The ConfigMap is not garbage collected, this tests that even if the cleaner is not
50+
// implemented the workflow cleanup still called even if there is explicit invocation
51+
await().untilAsserted(() -> {
52+
assertThat(extension.get(ConfigMap.class, RESOURCE_NAME)).isNull();
53+
});
54+
}
55+
56+
WorkflowExplicitInvocationCustomResource testResource() {
57+
var res = new WorkflowExplicitInvocationCustomResource();
58+
res.setMetadata(new ObjectMetaBuilder()
59+
.withName(RESOURCE_NAME)
60+
.build());
61+
res.setSpec(new WorkflowExplicitInvocationSpec());
62+
res.getSpec().setValue("initial value");
63+
return res;
64+
}
65+
66+
}

Diff for: ‎operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/bulkdependent/ManagedBulkDependentWithReadyConditionReconciler.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public UpdateControl<BulkDependentTestCustomResource> reconcile(
1919
Context<BulkDependentTestCustomResource> context) throws Exception {
2020
numberOfExecutions.incrementAndGet();
2121

22-
var ready = context.managedDependentResourceContext().getWorkflowReconcileResult()
22+
var ready = context.managedWorkflowAndDependentResourceContext().getWorkflowReconcileResult()
2323
.allDependentResourcesReady();
2424

2525

Diff for: ‎operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/complexdependent/ComplexDependentReconciler.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public class ComplexDependentReconciler implements Reconciler<ComplexDependentCu
4040
public UpdateControl<ComplexDependentCustomResource> reconcile(
4141
ComplexDependentCustomResource resource,
4242
Context<ComplexDependentCustomResource> context) throws Exception {
43-
var ready = context.managedDependentResourceContext().getWorkflowReconcileResult()
43+
var ready = context.managedWorkflowAndDependentResourceContext().getWorkflowReconcileResult()
4444
.allDependentResourcesReady();
4545

4646
var status = Objects.requireNonNullElseGet(resource.getStatus(), ComplexDependentStatus::new);

Diff for: ‎operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/workflowallfeature/WorkflowAllFeatureReconciler.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public UpdateControl<WorkflowAllFeatureCustomResource> reconcile(
3535
}
3636
resource.getStatus()
3737
.setReady(
38-
context.managedDependentResourceContext()
38+
context.managedWorkflowAndDependentResourceContext()
3939
.getWorkflowReconcileResult()
4040
.allDependentResourcesReady());
4141
return UpdateControl.patchStatus(resource);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.javaoperatorsdk.operator.sample.workflowexplicitcleanup;
2+
3+
import java.util.Map;
4+
5+
import io.fabric8.kubernetes.api.model.ConfigMap;
6+
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
7+
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
8+
import io.javaoperatorsdk.operator.api.reconciler.Context;
9+
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDNoGCKubernetesDependentResource;
10+
11+
public class ConfigMapDependent extends
12+
CRUDNoGCKubernetesDependentResource<ConfigMap, WorkflowExplicitCleanupCustomResource> {
13+
14+
public ConfigMapDependent() {
15+
super(ConfigMap.class);
16+
}
17+
18+
@Override
19+
protected ConfigMap desired(WorkflowExplicitCleanupCustomResource primary,
20+
Context<WorkflowExplicitCleanupCustomResource> context) {
21+
return new ConfigMapBuilder()
22+
.withMetadata(new ObjectMetaBuilder()
23+
.withName(primary.getMetadata().getName())
24+
.withNamespace(primary.getMetadata().getNamespace())
25+
.build())
26+
.withData(Map.of("key", "val"))
27+
.build();
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.javaoperatorsdk.operator.sample.workflowexplicitcleanup;
2+
3+
import io.fabric8.kubernetes.api.model.Namespaced;
4+
import io.fabric8.kubernetes.client.CustomResource;
5+
import io.fabric8.kubernetes.model.annotation.Group;
6+
import io.fabric8.kubernetes.model.annotation.ShortNames;
7+
import io.fabric8.kubernetes.model.annotation.Version;
8+
9+
@Group("sample.javaoperatorsdk")
10+
@Version("v1")
11+
@ShortNames("wec")
12+
public class WorkflowExplicitCleanupCustomResource
13+
extends CustomResource<Void, Void>
14+
implements Namespaced {
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package io.javaoperatorsdk.operator.sample.workflowexplicitcleanup;
2+
3+
import io.javaoperatorsdk.operator.api.reconciler.*;
4+
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
5+
6+
@Workflow(explicitInvocation = true,
7+
dependents = @Dependent(type = ConfigMapDependent.class))
8+
@ControllerConfiguration
9+
public class WorkflowExplicitCleanupReconciler
10+
implements Reconciler<WorkflowExplicitCleanupCustomResource>,
11+
Cleaner<WorkflowExplicitCleanupCustomResource> {
12+
13+
@Override
14+
public UpdateControl<WorkflowExplicitCleanupCustomResource> reconcile(
15+
WorkflowExplicitCleanupCustomResource resource,
16+
Context<WorkflowExplicitCleanupCustomResource> context) {
17+
18+
context.managedWorkflowAndDependentResourceContext().reconcileManagedWorkflow();
19+
20+
return UpdateControl.noUpdate();
21+
}
22+
23+
@Override
24+
public DeleteControl cleanup(WorkflowExplicitCleanupCustomResource resource,
25+
Context<WorkflowExplicitCleanupCustomResource> context) {
26+
27+
context.managedWorkflowAndDependentResourceContext().cleanupManageWorkflow();
28+
// this can be checked
29+
// context.managedWorkflowAndDependentResourceContext().getWorkflowCleanupResult()
30+
return DeleteControl.defaultDelete();
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.javaoperatorsdk.operator.sample.workflowexplicitcleanup;
2+
3+
public class WorkflowExplicitCleanupSpec {
4+
5+
private String value;
6+
7+
public String getValue() {
8+
return value;
9+
}
10+
11+
public WorkflowExplicitCleanupSpec setValue(String value) {
12+
this.value = value;
13+
return this;
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package io.javaoperatorsdk.operator.sample.workflowexplicitinvocation;
2+
3+
import java.util.Map;
4+
5+
import io.fabric8.kubernetes.api.model.ConfigMap;
6+
import io.fabric8.kubernetes.api.model.ConfigMapBuilder;
7+
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
8+
import io.javaoperatorsdk.operator.api.reconciler.Context;
9+
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDNoGCKubernetesDependentResource;
10+
11+
public class ConfigMapDependent extends
12+
CRUDNoGCKubernetesDependentResource<ConfigMap, WorkflowExplicitInvocationCustomResource> {
13+
14+
public ConfigMapDependent() {
15+
super(ConfigMap.class);
16+
}
17+
18+
@Override
19+
protected ConfigMap desired(WorkflowExplicitInvocationCustomResource primary,
20+
Context<WorkflowExplicitInvocationCustomResource> context) {
21+
return new ConfigMapBuilder()
22+
.withMetadata(new ObjectMetaBuilder()
23+
.withName(primary.getMetadata().getName())
24+
.withNamespace(primary.getMetadata().getNamespace())
25+
.build())
26+
.withData(Map.of("key", primary.getSpec().getValue()))
27+
.build();
28+
}
29+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.javaoperatorsdk.operator.sample.workflowexplicitinvocation;
2+
3+
import io.fabric8.kubernetes.api.model.Namespaced;
4+
import io.fabric8.kubernetes.client.CustomResource;
5+
import io.fabric8.kubernetes.model.annotation.Group;
6+
import io.fabric8.kubernetes.model.annotation.ShortNames;
7+
import io.fabric8.kubernetes.model.annotation.Version;
8+
9+
@Group("sample.javaoperatorsdk")
10+
@Version("v1")
11+
@ShortNames("wei")
12+
public class WorkflowExplicitInvocationCustomResource
13+
extends CustomResource<WorkflowExplicitInvocationSpec, Void>
14+
implements Namespaced {
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package io.javaoperatorsdk.operator.sample.workflowexplicitinvocation;
2+
3+
import java.util.concurrent.atomic.AtomicInteger;
4+
5+
import io.javaoperatorsdk.operator.api.reconciler.*;
6+
import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
7+
8+
@Workflow(explicitInvocation = true,
9+
dependents = @Dependent(type = ConfigMapDependent.class))
10+
@ControllerConfiguration
11+
public class WorkflowExplicitInvocationReconciler
12+
implements Reconciler<WorkflowExplicitInvocationCustomResource> {
13+
14+
private final AtomicInteger numberOfExecutions = new AtomicInteger(0);
15+
16+
private volatile boolean invokeWorkflow = false;
17+
18+
@Override
19+
public UpdateControl<WorkflowExplicitInvocationCustomResource> reconcile(
20+
WorkflowExplicitInvocationCustomResource resource,
21+
Context<WorkflowExplicitInvocationCustomResource> context) {
22+
23+
numberOfExecutions.addAndGet(1);
24+
if (invokeWorkflow) {
25+
context.managedWorkflowAndDependentResourceContext().reconcileManagedWorkflow();
26+
}
27+
28+
29+
return UpdateControl.noUpdate();
30+
}
31+
32+
public int getNumberOfExecutions() {
33+
return numberOfExecutions.get();
34+
}
35+
36+
public void setInvokeWorkflow(boolean invokeWorkflow) {
37+
this.invokeWorkflow = invokeWorkflow;
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.javaoperatorsdk.operator.sample.workflowexplicitinvocation;
2+
3+
public class WorkflowExplicitInvocationSpec {
4+
5+
private String value;
6+
7+
public String getValue() {
8+
return value;
9+
}
10+
11+
public WorkflowExplicitInvocationSpec setValue(String value) {
12+
this.value = value;
13+
return this;
14+
}
15+
}

0 commit comments

Comments
 (0)
Please sign in to comment.