expectedType, String eventS
* If a workflow has an activation condition there can be event sources which are only
* registered if the activation condition holds, but to provide a consistent API we return an
* Optional instead of throwing an exception.
- *
+ *
* Note that not only the resource which has an activation condition might not be registered
* but dependents which depend on it.
*/
@@ -116,4 +116,8 @@ public DefaultContext setRetryInfo(RetryInfo retryInfo) {
this.retryInfo = retryInfo;
return this;
}
+
+ public P getPrimaryResource() {
+ return primaryResource;
+ }
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java
index 1ad3b65910..8c502d41ff 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcher.java
@@ -86,7 +86,7 @@ private PostExecutionControl
handleDispatch(ExecutionScope
executionScope)
}
Context
context =
- new DefaultContext<>(executionScope.getRetryInfo(), controller, originalResource);
+ new DefaultContext<>(executionScope.getRetryInfo(), controller, resourceForExecution);
if (markedForDeletion) {
return handleCleanup(resourceForExecution, originalResource, context);
} else {
@@ -234,29 +234,29 @@ private void updatePostExecutionControlWithReschedule(
baseControl.getScheduleDelay().ifPresent(postExecutionControl::withReSchedule);
}
- private PostExecutionControl
handleCleanup(P resource,
+ private PostExecutionControl
handleCleanup(P resourceForExecution,
P originalResource, Context
context) {
if (log.isDebugEnabled()) {
log.debug(
"Executing delete for resource: {} with version: {}",
- ResourceID.fromResource(resource),
- getVersion(resource));
+ ResourceID.fromResource(resourceForExecution),
+ getVersion(resourceForExecution));
}
- DeleteControl deleteControl = controller.cleanup(resource, context);
+ DeleteControl deleteControl = controller.cleanup(resourceForExecution, context);
final var useFinalizer = controller.useFinalizer();
if (useFinalizer) {
// note that we don't reschedule here even if instructed. Removing finalizer means that
- // cleanup is finished, nothing left to done
+ // cleanup is finished, nothing left to be done
final var finalizerName = configuration().getFinalizerName();
- if (deleteControl.isRemoveFinalizer() && resource.hasFinalizer(finalizerName)) {
- P customResource = conflictRetryingPatch(resource, originalResource, r -> {
+ if (deleteControl.isRemoveFinalizer() && resourceForExecution.hasFinalizer(finalizerName)) {
+ P customResource = conflictRetryingPatch(resourceForExecution, originalResource, r -> {
// the operator might not be allowed to retrieve the resource on a retry, e.g. when its
// permissions are removed by deleting the namespace concurrently
if (r == null) {
log.warn(
"Could not remove finalizer on null resource: {} with version: {}",
- getUID(resource),
- getVersion(resource));
+ getUID(resourceForExecution),
+ getVersion(resourceForExecution));
return false;
}
return r.removeFinalizer(finalizerName);
@@ -266,8 +266,8 @@ private PostExecutionControl
handleCleanup(P resource,
}
log.debug(
"Skipping finalizer remove for resource: {} with version: {}. delete control: {}, uses finalizer: {}",
- getUID(resource),
- getVersion(resource),
+ getUID(resourceForExecution),
+ getVersion(resourceForExecution),
deleteControl,
useFinalizer);
PostExecutionControl
postExecutionControl = PostExecutionControl.defaultDispatch();
diff --git a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java
index efec8c4228..e5fe1c5882 100644
--- a/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java
+++ b/operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/event/ReconciliationDispatcherTest.java
@@ -7,6 +7,8 @@
import java.util.function.BiFunction;
import java.util.function.Supplier;
+import io.fabric8.kubernetes.client.utils.KubernetesSerialization;
+import io.javaoperatorsdk.operator.api.reconciler.DefaultContext;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
@@ -68,6 +70,9 @@ void setup() {
}
static void initConfigService(boolean useSSA) {
+ initConfigService(useSSA,true);
+ }
+ static void initConfigService(boolean useSSA, boolean noCloning) {
/*
* We need this for mock reconcilers to properly generate the expected UpdateControl: without
* this, calls such as `when(reconciler.reconcile(eq(testCustomResource),
@@ -77,14 +82,18 @@ static void initConfigService(boolean useSSA) {
*/
configurationService =
ConfigurationService.newOverriddenConfigurationService(new BaseConfigurationService(),
- overrider -> overrider.checkingCRDAndValidateLocalModel(false)
+ overrider -> overrider.checkingCRDAndValidateLocalModel(false)
+
.withResourceCloner(new Cloner() {
@Override
public R clone(R object) {
+ if (noCloning) {
return object;
+ }else {
+ return new KubernetesSerialization().clone(object);
}
- })
- .withUseSSAToPatchPrimaryResource(useSSA));
+ }})
+ .withUseSSAToPatchPrimaryResource(useSSA));
}
private ReconciliationDispatcher init(R customResource,
@@ -659,10 +668,24 @@ void reSchedulesFromErrorHandler() {
}
@Test
- void addsFinalizerToPatchWithSSA() {
+ void reconcilerContextUsesTheSameInstanceOfResourceAsParam() {
+ initConfigService(false,false);
- }
+ final ReconciliationDispatcher dispatcher =
+ init(testCustomResource, reconciler, null, customResourceFacade, true);
+ testCustomResource.addFinalizer(DEFAULT_FINALIZER);
+ ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(DefaultContext.class);
+ ArgumentCaptor customResourceCaptor = ArgumentCaptor.forClass(TestCustomResource.class);
+
+ dispatcher.handleExecution(executionScopeWithCREvent(testCustomResource));
+ verify(reconciler, times(1))
+ .reconcile(customResourceCaptor.capture(), contextArgumentCaptor.capture());
+
+ assertThat(contextArgumentCaptor.getValue().getPrimaryResource())
+ .isSameAs(customResourceCaptor.getValue())
+ .isNotSameAs(testCustomResource);
+ }
private ObservedGenCustomResource createObservedGenCustomResource() {
ObservedGenCustomResource observedGenCustomResource = new ObservedGenCustomResource();
diff --git a/operator-framework-junit5/pom.xml b/operator-framework-junit5/pom.xml
index c03a20ad93..465bbc0d20 100644
--- a/operator-framework-junit5/pom.xml
+++ b/operator-framework-junit5/pom.xml
@@ -4,7 +4,7 @@
io.javaoperatorsdk
java-operator-sdk
- 5.0.1-SNAPSHOT
+ 5.0.2-SNAPSHOT
operator-framework-junit-5
diff --git a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java
index a2c92bf48b..45cd85b468 100644
--- a/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java
+++ b/operator-framework-junit5/src/main/java/io/javaoperatorsdk/operator/junit/LocallyRunOperatorExtension.java
@@ -8,14 +8,21 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
+import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Deque;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
+import io.fabric8.kubernetes.client.dsl.NamespaceListVisitFromServerGetDeleteRecreateWaitApplicable;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -40,6 +47,9 @@
public class LocallyRunOperatorExtension extends AbstractOperatorExtension {
private static final Logger LOGGER = LoggerFactory.getLogger(LocallyRunOperatorExtension.class);
+ private static final int CRD_DELETE_TIMEOUT = 1000;
+ private static final Set appliedCRDs = new HashSet<>();
+ private static final boolean deleteCRDs = Boolean.parseBoolean(System.getProperty("testsuite.deleteCRDs", "true"));
private final Operator operator;
private final List reconcilers;
@@ -144,6 +154,7 @@ private static void applyCrd(String crdString, String path, KubernetesClient cli
LOGGER.debug("Applying CRD: {}", crdString);
final var crd = client.load(new ByteArrayInputStream(crdString.getBytes()));
crd.serverSideApply();
+ appliedCRDs.add(new AppliedCRD(crdString, path));
Thread.sleep(CRD_READY_WAIT); // readiness is not applicable for CRD, just wait a little
LOGGER.debug("Applied CRD with path: {}", path);
} catch (InterruptedException ex) {
@@ -290,6 +301,16 @@ protected void before(ExtensionContext context) {
protected void after(ExtensionContext context) {
super.after(context);
+ var kubernetesClient = getKubernetesClient();
+
+ var iterator = appliedCRDs.iterator();
+ while (iterator.hasNext()) {
+ deleteCrd(iterator.next(), kubernetesClient);
+ iterator.remove();
+ }
+
+ kubernetesClient.close();
+
try {
this.operator.stop();
} catch (Exception e) {
@@ -306,6 +327,23 @@ protected void after(ExtensionContext context) {
localPortForwards.clear();
}
+ private void deleteCrd(AppliedCRD appliedCRD, KubernetesClient client) {
+ if (!deleteCRDs) {
+ LOGGER.debug("Skipping deleting CRD because of configuration: {}", appliedCRD);
+ return;
+ }
+ try {
+ LOGGER.debug("Deleting CRD: {}", appliedCRD.crdString);
+ final var crd = client.load(new ByteArrayInputStream(appliedCRD.crdString.getBytes()));
+ crd.withTimeoutInMillis(CRD_DELETE_TIMEOUT).delete();
+ LOGGER.debug("Deleted CRD with path: {}", appliedCRD.path);
+ } catch (Exception ex) {
+ throw new IllegalStateException("Cannot delete CRD yaml: " + appliedCRD.path, ex);
+ }
+ }
+
+ private record AppliedCRD(String crdString, String path) {}
+
@SuppressWarnings("rawtypes")
public static class Builder extends AbstractBuilder {
private final List reconcilers;
diff --git a/operator-framework/pom.xml b/operator-framework/pom.xml
index 3b8e9bf31c..1f505fae78 100644
--- a/operator-framework/pom.xml
+++ b/operator-framework/pom.xml
@@ -4,7 +4,7 @@
io.javaoperatorsdk
java-operator-sdk
- 5.0.1-SNAPSHOT
+ 5.0.2-SNAPSHOT
operator-framework
diff --git a/pom.xml b/pom.xml
index 4c35c76a32..3d894384b2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
io.javaoperatorsdk
java-operator-sdk
- 5.0.1-SNAPSHOT
+ 5.0.2-SNAPSHOT
pom
Operator SDK for Java
Java SDK for implementing Kubernetes operators
@@ -71,7 +71,7 @@
3.27.3
4.2.2
2.7.3
- 1.14.3
+ 1.14.4
3.2.0
0.9.14
2.18.0
@@ -313,38 +313,6 @@
-
- com.diffplug.spotless
- spotless-maven-plugin
-
-
-
- pom.xml
- ./**/pom.xml
-
-
- false
-
-
-
-
- contributing/eclipse-google-style.xml
-
-
- contributing/eclipse.importorder
-
-
-
-
-
-
-
- apply
-
- compile
-
-
-
org.apache.maven.plugins
maven-surefire-plugin
@@ -362,6 +330,50 @@
+
+ spotless
+
+
+ contributing
+
+
+
+
+
+ com.diffplug.spotless
+ spotless-maven-plugin
+
+
+
+ pom.xml
+ ./**/pom.xml
+
+
+ false
+
+
+
+
+ contributing/eclipse-google-style.xml
+
+
+ contributing/eclipse.importorder
+
+
+
+
+
+
+
+ apply
+
+ compile
+
+
+
+
+
+
integration-tests
diff --git a/sample-operators/controller-namespace-deletion/pom.xml b/sample-operators/controller-namespace-deletion/pom.xml
index 532853b311..c5f6e7abc3 100644
--- a/sample-operators/controller-namespace-deletion/pom.xml
+++ b/sample-operators/controller-namespace-deletion/pom.xml
@@ -5,7 +5,7 @@
io.javaoperatorsdk
sample-operators
- 5.0.1-SNAPSHOT
+ 5.0.2-SNAPSHOT
sample-controller-namespace-deletion
diff --git a/sample-operators/leader-election/pom.xml b/sample-operators/leader-election/pom.xml
index d35018c1de..42b54bf5be 100644
--- a/sample-operators/leader-election/pom.xml
+++ b/sample-operators/leader-election/pom.xml
@@ -5,7 +5,7 @@
io.javaoperatorsdk
sample-operators
- 5.0.1-SNAPSHOT
+ 5.0.2-SNAPSHOT
sample-leader-election
diff --git a/sample-operators/mysql-schema/pom.xml b/sample-operators/mysql-schema/pom.xml
index b96230370c..ecd3398a76 100644
--- a/sample-operators/mysql-schema/pom.xml
+++ b/sample-operators/mysql-schema/pom.xml
@@ -5,7 +5,7 @@
io.javaoperatorsdk
sample-operators
- 5.0.1-SNAPSHOT
+ 5.0.2-SNAPSHOT
sample-mysql-schema-operator
diff --git a/sample-operators/pom.xml b/sample-operators/pom.xml
index 1a214c0b2a..7b13dc5d7e 100644
--- a/sample-operators/pom.xml
+++ b/sample-operators/pom.xml
@@ -5,7 +5,7 @@
io.javaoperatorsdk
java-operator-sdk
- 5.0.1-SNAPSHOT
+ 5.0.2-SNAPSHOT
sample-operators
diff --git a/sample-operators/tomcat-operator/pom.xml b/sample-operators/tomcat-operator/pom.xml
index 2b0dccc1ec..9a126f5995 100644
--- a/sample-operators/tomcat-operator/pom.xml
+++ b/sample-operators/tomcat-operator/pom.xml
@@ -5,7 +5,7 @@
io.javaoperatorsdk
sample-operators
- 5.0.1-SNAPSHOT
+ 5.0.2-SNAPSHOT
sample-tomcat-operator
diff --git a/sample-operators/tomcat-operator/src/test/java/io/javaoperatorsdk/operator/sample/TomcatOperatorE2E.java b/sample-operators/tomcat-operator/src/test/java/io/javaoperatorsdk/operator/sample/TomcatOperatorE2E.java
index 929af47e5d..3095e7db8c 100644
--- a/sample-operators/tomcat-operator/src/test/java/io/javaoperatorsdk/operator/sample/TomcatOperatorE2E.java
+++ b/sample-operators/tomcat-operator/src/test/java/io/javaoperatorsdk/operator/sample/TomcatOperatorE2E.java
@@ -117,6 +117,11 @@ void test() {
throw new AssertionError(ex);
}
});
+
+ log.info("Deleting test Tomcat object: {}", tomcat);
+ tomcatClient.inNamespace(operator.getNamespace()).resource(tomcat).delete();
+ log.info("Deleting test Webapp object: {}", webapp1);
+ webappClient.inNamespace(operator.getNamespace()).resource(webapp1).delete();
}
}
diff --git a/sample-operators/webpage/pom.xml b/sample-operators/webpage/pom.xml
index ac9a5808da..5128cf0d0f 100644
--- a/sample-operators/webpage/pom.xml
+++ b/sample-operators/webpage/pom.xml
@@ -5,7 +5,7 @@
io.javaoperatorsdk
sample-operators
- 5.0.1-SNAPSHOT
+ 5.0.2-SNAPSHOT
sample-webpage-operator