diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
index 2422f6ef74..86efb457c5 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java
@@ -9,7 +9,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.fabric8.kubernetes.api.model.Secret;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.ConfigBuilder;
import io.fabric8.kubernetes.client.CustomResource;
@@ -19,6 +21,7 @@
import io.javaoperatorsdk.operator.api.monitoring.Metrics;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
import io.javaoperatorsdk.operator.api.reconciler.dependent.DependentResourceFactory;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
import io.javaoperatorsdk.operator.processing.dependent.workflow.ManagedWorkflowFactory;
import static io.javaoperatorsdk.operator.api.config.ExecutorServiceManager.newThreadPoolExecutor;
@@ -335,7 +338,7 @@ default ExecutorServiceManager getExecutorServiceManager() {
* resources are created/updated and match was change to use
* Server-Side
* Apply (SSA) by default.
- *
+ *
* SSA based create/update can be still used with the legacy matching, just overriding the match
* method of Kubernetes Dependent Resource.
*
@@ -345,4 +348,20 @@ default boolean ssaBasedCreateUpdateMatchForDependentResources() {
return true;
}
+ /**
+ * Returns the set of default resources for which Server-Side Apply (SSA) will not be used, even
+ * if it is the default behavior for dependent resources as specified by
+ * {@link #ssaBasedCreateUpdateMatchForDependentResources()}. The exception to this is in the case
+ * where the use of SSA is explicitly enabled on the dependent resource directly using
+ * {@link KubernetesDependent#useSSA()}.
+ *
+ * By default, SSA is disabled for {@link ConfigMap} and {@link Secret} resources.
+ *
+ * @return The set of resource types for which SSA will not be used
+ * @since 4.4.0
+ */
+ default Set> defaultNonSSAResource() {
+ return Set.of(ConfigMap.class, Secret.class);
+ }
+
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java
index ebac41f640..15418aed5e 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java
@@ -9,6 +9,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.operator.api.monitoring.Metrics;
@@ -35,6 +36,7 @@ public class ConfigurationServiceOverrider {
private Duration cacheSyncTimeout;
private ResourceClassResolver resourceClassResolver;
private Boolean ssaBasedCreateUpdateMatchForDependentResources;
+ private Set> defaultNonSSAResource;
ConfigurationServiceOverrider(ConfigurationService original) {
this.original = original;
@@ -150,6 +152,12 @@ public ConfigurationServiceOverrider withSSABasedCreateUpdateMatchForDependentRe
return this;
}
+ public ConfigurationServiceOverrider withDefaultNonSSAResource(
+ Set> defaultNonSSAResource) {
+ this.defaultNonSSAResource = defaultNonSSAResource;
+ return this;
+ }
+
public ConfigurationService build() {
return new BaseConfigurationService(original.getVersion(), cloner, client) {
@Override
@@ -256,6 +264,12 @@ public boolean ssaBasedCreateUpdateMatchForDependentResources() {
? ssaBasedCreateUpdateMatchForDependentResources
: super.ssaBasedCreateUpdateMatchForDependentResources();
}
+
+ @Override
+ public Set> defaultNonSSAResource() {
+ return defaultNonSSAResource != null ? defaultNonSSAResource
+ : super.defaultNonSSAResource();
+ }
};
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java
new file mode 100644
index 0000000000..45b781af7a
--- /dev/null
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/DesiredResourceSanitizer.java
@@ -0,0 +1,47 @@
+package io.javaoperatorsdk.operator.processing.dependent.kubernetes;
+
+import io.fabric8.kubernetes.api.model.HasMetadata;
+import io.fabric8.kubernetes.api.model.PersistentVolumeClaimStatus;
+import io.fabric8.kubernetes.api.model.Secret;
+import io.fabric8.kubernetes.api.model.apps.StatefulSet;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+
+public class DesiredResourceSanitizer {
+
+ private DesiredResourceSanitizer() {}
+
+ public static void sanitizeDesired(R desired, R actual, P primary,
+ Context context, boolean useSSA) {
+ if (useSSA) {
+ if (desired instanceof StatefulSet) {
+ fillDefaultsOnVolumeClaimTemplate((StatefulSet) desired);
+ }
+ if (desired instanceof Secret) {
+ checkIfStringDataUsed((Secret) desired);
+ }
+ }
+ }
+
+ private static void checkIfStringDataUsed(Secret secret) {
+ if (secret.getStringData() != null && !secret.getStringData().isEmpty()) {
+ throw new IllegalStateException(
+ "There is a known issue using StringData with SSA. Use data instead.");
+ }
+ }
+
+ private static void fillDefaultsOnVolumeClaimTemplate(StatefulSet statefulSet) {
+ if (!statefulSet.getSpec().getVolumeClaimTemplates().isEmpty()) {
+ statefulSet.getSpec().getVolumeClaimTemplates().forEach(t -> {
+ if (t.getSpec().getVolumeMode() == null) {
+ t.getSpec().setVolumeMode("Filesystem");
+ }
+ if (t.getStatus() == null) {
+ t.setStatus(new PersistentVolumeClaimStatus());
+ }
+ if (t.getStatus().getPhase() == null) {
+ t.getStatus().setPhase("pending");
+ }
+ });
+ }
+ }
+}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java
index 7fadcc6940..22ec5a48f9 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResource.java
@@ -103,18 +103,19 @@ public void configureWith(InformerEventSource informerEventSource) {
}
@SuppressWarnings("unused")
- public R create(R target, P primary, Context context) {
+ public R create(R desired, P primary, Context
context) {
if (useSSA(context)) {
// setting resource version for SSA so only created if it doesn't exist already
var createIfNotExisting = kubernetesDependentResourceConfig == null
? KubernetesDependentResourceConfig.DEFAULT_CREATE_RESOURCE_ONLY_IF_NOT_EXISTING_WITH_SSA
: kubernetesDependentResourceConfig.createResourceOnlyIfNotExistingWithSSA();
if (createIfNotExisting) {
- target.getMetadata().setResourceVersion("1");
+ desired.getMetadata().setResourceVersion("1");
}
}
- addMetadata(false, null, target, primary);
- final var resource = prepare(target, primary, "Creating");
+ addMetadata(false, null, desired, primary);
+ sanitizeDesired(desired, null, primary, context);
+ final var resource = prepare(desired, primary, "Creating");
return useSSA(context)
? resource
.fieldManager(context.getControllerConfiguration().fieldManager())
@@ -123,19 +124,20 @@ public R create(R target, P primary, Context
context) {
: resource.create();
}
- public R update(R actual, R target, P primary, Context
context) {
+ public R update(R actual, R desired, P primary, Context
context) {
if (log.isDebugEnabled()) {
log.debug("Updating actual resource: {} version: {}", ResourceID.fromResource(actual),
actual.getMetadata().getResourceVersion());
}
R updatedResource;
- addMetadata(false, actual, target, primary);
+ addMetadata(false, actual, desired, primary);
+ sanitizeDesired(desired, actual, primary, context);
if (useSSA(context)) {
- updatedResource = prepare(target, primary, "Updating")
+ updatedResource = prepare(desired, primary, "Updating")
.fieldManager(context.getControllerConfiguration().fieldManager())
.forceConflicts().serverSideApply();
} else {
- var updatedActual = updaterMatcher.updateResource(actual, target, context);
+ var updatedActual = updaterMatcher.updateResource(actual, desired, context);
updatedResource = prepare(updatedActual, primary, "Updating").update();
}
log.debug("Resource version after update: {}",
@@ -146,6 +148,7 @@ public R update(R actual, R target, P primary, Context
context) {
@Override
public Result match(R actualResource, P primary, Context context) {
final var desired = desired(primary, context);
+ sanitizeDesired(desired, actualResource, primary, context);
return match(actualResource, desired, primary, updaterMatcher, context);
}
@@ -189,9 +192,18 @@ protected void addMetadata(boolean forMatch, R actualResource, final R target, P
addReferenceHandlingMetadata(target, primary);
}
- private boolean useSSA(Context
context) {
+ protected void sanitizeDesired(R desired, R actual, P primary, Context
context) {
+ DesiredResourceSanitizer.sanitizeDesired(desired, actual, primary, context, useSSA(context));
+ }
+
+ protected boolean useSSA(Context
context) {
Optional useSSAConfig =
configuration().flatMap(KubernetesDependentResourceConfig::useSSA);
+ var configService = context.getControllerConfiguration().getConfigurationService();
+ // don't use SSA for certain resources by default, only if explicitly overriden
+ if (useSSAConfig.isEmpty() && configService.defaultNonSSAResource().contains(resourceType())) {
+ return false;
+ }
return useSSAConfig.orElse(context.getControllerConfiguration().getConfigurationService()
.ssaBasedCreateUpdateMatchForDependentResources());
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java
index 8bdb8a47a5..a18d8b8a41 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/KubernetesDependentResourceConfigBuilder.java
@@ -2,6 +2,7 @@
import java.util.Set;
+import io.javaoperatorsdk.operator.api.reconciler.Constants;
import io.javaoperatorsdk.operator.api.reconciler.ResourceDiscriminator;
import io.javaoperatorsdk.operator.processing.event.source.filter.GenericFilter;
import io.javaoperatorsdk.operator.processing.event.source.filter.OnAddFilter;
@@ -10,7 +11,7 @@
public final class KubernetesDependentResourceConfigBuilder {
- private Set namespaces;
+ private Set namespaces = Constants.SAME_AS_CONTROLLER_NAMESPACES_SET;
private String labelSelector;
private boolean createResourceOnlyIfNotExistingWithSSA;
private ResourceDiscriminator resourceDiscriminator;
@@ -77,7 +78,8 @@ public KubernetesDependentResourceConfigBuilder withGenericFilter(
}
public KubernetesDependentResourceConfig build() {
- return new KubernetesDependentResourceConfig<>(namespaces, labelSelector, false,
+ return new KubernetesDependentResourceConfig<>(namespaces, labelSelector,
+ namespaces != Constants.SAME_AS_CONTROLLER_NAMESPACES_SET,
createResourceOnlyIfNotExistingWithSSA, resourceDiscriminator, useSSA, onAddFilter,
onUpdateFilter, onDeleteFilter, genericFilter);
}
diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java
index f4718b45c3..442119a822 100644
--- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java
+++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/dependent/kubernetes/SSABasedGenericKubernetesResourceMatcher.java
@@ -1,14 +1,7 @@
package io.javaoperatorsdk.operator.processing.dependent.kubernetes;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
import java.util.Map.Entry;
-import java.util.Optional;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
import java.util.stream.Collectors;
import org.slf4j.Logger;
@@ -159,7 +152,7 @@ private static void fillResultsAndTraverseFurther(Map result,
Object managedFieldValue) {
var emptyMapValue = new HashMap();
result.put(keyInActual, emptyMapValue);
- var actualMapValue = actualMap.get(keyInActual);
+ var actualMapValue = actualMap.getOrDefault(keyInActual, Collections.emptyMap());
log.debug("key: {} actual map value: {} managedFieldValue: {}", keyInActual,
actualMapValue, managedFieldValue);
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java
index 7e226eca38..0eabc07c97 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/DependentSSAMigrationIT.java
@@ -144,9 +144,10 @@ private DependnetSSACustomResource reconcileWithLegacyOperator(Operator legacyOp
private Operator createOperator(KubernetesClient client, boolean legacyDependentHandling,
String fieldManager) {
Operator operator = new Operator(client,
- o -> o.withSSABasedCreateUpdateMatchForDependentResources(!legacyDependentHandling)
- .withCloseClientOnStop(false));
- operator.register(new DependentSSAReconciler(), o -> {
+ o -> o.withCloseClientOnStop(false));
+ var reconciler = new DependentSSAReconciler(!legacyDependentHandling);
+ reconciler.setKubernetesClient(client);
+ operator.register(reconciler, o -> {
o.settingNamespace(namespace);
if (fieldManager != null) {
o.withFieldManager(fieldManager);
@@ -155,7 +156,6 @@ private Operator createOperator(KubernetesClient client, boolean legacyDependent
return operator;
}
-
public DependnetSSACustomResource testResource() {
DependnetSSACustomResource resource = new DependnetSSACustomResource();
resource.setMetadata(new ObjectMetaBuilder()
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/StatefulSetDesiredSanitizerIT.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/StatefulSetDesiredSanitizerIT.java
new file mode 100644
index 0000000000..5313fb7dfb
--- /dev/null
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/StatefulSetDesiredSanitizerIT.java
@@ -0,0 +1,57 @@
+package io.javaoperatorsdk.operator;
+
+import java.time.Duration;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
+import io.fabric8.kubernetes.api.model.apps.StatefulSet;
+import io.javaoperatorsdk.operator.junit.LocallyRunOperatorExtension;
+import io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer.StatefulSetDesiredSanitizerCustomResource;
+import io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer.StatefulSetDesiredSanitizerDependentResource;
+import io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer.StatefulSetDesiredSanitizerReconciler;
+import io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer.StatefulSetDesiredSanitizerSpec;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.awaitility.Awaitility.await;
+
+public class StatefulSetDesiredSanitizerIT {
+
+ public static final String TEST_1 = "test1";
+
+ @RegisterExtension
+ LocallyRunOperatorExtension extension =
+ LocallyRunOperatorExtension.builder()
+ .withReconciler(new StatefulSetDesiredSanitizerReconciler())
+ .build();
+
+ @Test
+ void testSSAMatcher() {
+ var resource = extension.create(testResource());
+
+ await().pollDelay(Duration.ofMillis(200)).untilAsserted(() -> {
+ var statefulSet = extension.get(StatefulSet.class, TEST_1);
+ assertThat(statefulSet).isNotNull();
+ });
+ // make sure reconciliation happens at least once more
+ resource.getSpec().setValue("changed value");
+ extension.replace(resource);
+
+ await().untilAsserted(
+ () -> assertThat(StatefulSetDesiredSanitizerDependentResource.nonMatchedAtLeastOnce)
+ .isFalse());
+ }
+
+ StatefulSetDesiredSanitizerCustomResource testResource() {
+ var res = new StatefulSetDesiredSanitizerCustomResource();
+ res.setMetadata(new ObjectMetaBuilder()
+ .withName(TEST_1)
+ .build());
+ res.setSpec(new StatefulSetDesiredSanitizerSpec());
+ res.getSpec().setValue("initial value");
+
+ return res;
+ }
+
+}
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java
index d5c48256f7..f84dfe4597 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/DependentSSAReconciler.java
@@ -1,21 +1,43 @@
package io.javaoperatorsdk.operator.sample.dependentssa;
+import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
+import io.fabric8.kubernetes.api.model.ConfigMap;
+import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.operator.api.reconciler.*;
-import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
+import io.javaoperatorsdk.operator.junit.KubernetesClientAware;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependentResourceConfigBuilder;
+import io.javaoperatorsdk.operator.processing.event.source.EventSource;
import io.javaoperatorsdk.operator.support.TestExecutionInfoProvider;
-@ControllerConfiguration(dependents = {@Dependent(type = SSAConfigMapDependent.class)})
+@ControllerConfiguration
public class DependentSSAReconciler
- implements Reconciler, TestExecutionInfoProvider {
+ implements Reconciler, TestExecutionInfoProvider,
+ KubernetesClientAware,
+ EventSourceInitializer {
private final AtomicInteger numberOfExecutions = new AtomicInteger(0);
+ private SSAConfigMapDependent ssaConfigMapDependent = new SSAConfigMapDependent();
+ private KubernetesClient kubernetesClient;
+
+ public DependentSSAReconciler() {
+ this(true);
+ }
+
+ public DependentSSAReconciler(boolean useSSA) {
+ ssaConfigMapDependent.configureWith(new KubernetesDependentResourceConfigBuilder()
+ .withUseSSA(useSSA)
+ .build());
+ }
+
@Override
public UpdateControl reconcile(
DependnetSSACustomResource resource,
Context context) {
+
+ ssaConfigMapDependent.reconcile(resource, context);
numberOfExecutions.addAndGet(1);
return UpdateControl.noUpdate();
}
@@ -24,4 +46,21 @@ public int getNumberOfExecutions() {
return numberOfExecutions.get();
}
+ @Override
+ public KubernetesClient getKubernetesClient() {
+ return kubernetesClient;
+ }
+
+ @Override
+ public void setKubernetesClient(KubernetesClient kubernetesClient) {
+ this.kubernetesClient = kubernetesClient;
+ ssaConfigMapDependent.setKubernetesClient(kubernetesClient);
+ }
+
+ @Override
+ public Map prepareEventSources(
+ EventSourceContext context) {
+ return EventSourceInitializer.nameEventSourcesFromDependentResource(context,
+ ssaConfigMapDependent);
+ }
}
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java
index 70f0ddcf15..806eccd717 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/dependentssa/SSAConfigMapDependent.java
@@ -33,10 +33,10 @@ protected ConfigMap desired(DependnetSSACustomResource primary,
}
@Override
- public ConfigMap update(ConfigMap actual, ConfigMap target,
+ public ConfigMap update(ConfigMap actual, ConfigMap desired,
DependnetSSACustomResource primary,
Context context) {
NUMBER_OF_UPDATES.incrementAndGet();
- return super.update(actual, target, primary, context);
+ return super.update(actual, desired, primary, context);
}
}
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/servicestrictmatcher/ServiceDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/servicestrictmatcher/ServiceDependentResource.java
index 1079642b33..deddf20263 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/servicestrictmatcher/ServiceDependentResource.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/servicestrictmatcher/ServiceDependentResource.java
@@ -53,10 +53,10 @@ public Matcher.Result match(Service actualResource,
}
@Override
- public Service update(Service actual, Service target,
+ public Service update(Service actual, Service desired,
ServiceStrictMatcherTestCustomResource primary,
Context context) {
updated.addAndGet(1);
- return super.update(actual, target, primary, context);
+ return super.update(actual, desired, primary, context);
}
}
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssalegacymatcher/ServiceDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssalegacymatcher/ServiceDependentResource.java
index 5230404ceb..a1f5f6faf0 100644
--- a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssalegacymatcher/ServiceDependentResource.java
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/ssalegacymatcher/ServiceDependentResource.java
@@ -45,17 +45,17 @@ public Result match(Service actualResource, SSALegacyMatcherCustomResou
// override just to check the exec count
@Override
- public Service update(Service actual, Service target, SSALegacyMatcherCustomResource primary,
+ public Service update(Service actual, Service desired, SSALegacyMatcherCustomResource primary,
Context context) {
createUpdateCount.addAndGet(1);
- return super.update(actual, target, primary, context);
+ return super.update(actual, desired, primary, context);
}
// override just to check the exec count
@Override
- public Service create(Service target, SSALegacyMatcherCustomResource primary,
+ public Service create(Service desired, SSALegacyMatcherCustomResource primary,
Context context) {
createUpdateCount.addAndGet(1);
- return super.create(target, primary, context);
+ return super.create(desired, primary, context);
}
}
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerCustomResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerCustomResource.java
new file mode 100644
index 0000000000..bf35304da0
--- /dev/null
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerCustomResource.java
@@ -0,0 +1,14 @@
+package io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer;
+
+import io.fabric8.kubernetes.api.model.Namespaced;
+import io.fabric8.kubernetes.client.CustomResource;
+import io.fabric8.kubernetes.model.annotation.Group;
+import io.fabric8.kubernetes.model.annotation.Version;
+
+@Group("sample.javaoperatorsdk")
+@Version("v1")
+public class StatefulSetDesiredSanitizerCustomResource
+ extends CustomResource
+ implements Namespaced {
+
+}
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerDependentResource.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerDependentResource.java
new file mode 100644
index 0000000000..12525c4c8d
--- /dev/null
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerDependentResource.java
@@ -0,0 +1,43 @@
+package io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer;
+
+import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
+import io.fabric8.kubernetes.api.model.apps.StatefulSet;
+import io.javaoperatorsdk.operator.ReconcilerUtils;
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
+
+public class StatefulSetDesiredSanitizerDependentResource
+ extends
+ CRUDKubernetesDependentResource {
+
+ public static volatile Boolean nonMatchedAtLeastOnce;
+
+ public StatefulSetDesiredSanitizerDependentResource() {
+ super(StatefulSet.class);
+ }
+
+ @Override
+ protected StatefulSet desired(StatefulSetDesiredSanitizerCustomResource primary,
+ Context context) {
+ var template =
+ ReconcilerUtils.loadYaml(StatefulSet.class, getClass(), "statefulset.yaml");
+ template.setMetadata(new ObjectMetaBuilder()
+ .withName(primary.getMetadata().getName())
+ .withNamespace(primary.getMetadata().getNamespace())
+ .build());
+ return template;
+ }
+
+ @Override
+ public Result match(StatefulSet actualResource,
+ StatefulSetDesiredSanitizerCustomResource primary,
+ Context context) {
+ var res = super.match(actualResource, primary, context);
+ if (!res.matched()) {
+ nonMatchedAtLeastOnce = true;
+ } else if (nonMatchedAtLeastOnce == null) {
+ nonMatchedAtLeastOnce = false;
+ }
+ return res;
+ }
+}
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerReconciler.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerReconciler.java
new file mode 100644
index 0000000000..c884619227
--- /dev/null
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerReconciler.java
@@ -0,0 +1,20 @@
+package io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer;
+
+import io.javaoperatorsdk.operator.api.reconciler.Context;
+import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
+import io.javaoperatorsdk.operator.api.reconciler.Reconciler;
+import io.javaoperatorsdk.operator.api.reconciler.UpdateControl;
+import io.javaoperatorsdk.operator.api.reconciler.dependent.Dependent;
+
+@ControllerConfiguration(
+ dependents = {@Dependent(type = StatefulSetDesiredSanitizerDependentResource.class)})
+public class StatefulSetDesiredSanitizerReconciler
+ implements Reconciler {
+
+ @Override
+ public UpdateControl reconcile(
+ StatefulSetDesiredSanitizerCustomResource resource,
+ Context context) throws Exception {
+ return UpdateControl.noUpdate();
+ }
+}
diff --git a/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerSpec.java b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerSpec.java
new file mode 100644
index 0000000000..3cca134108
--- /dev/null
+++ b/operator-framework/src/test/java/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/StatefulSetDesiredSanitizerSpec.java
@@ -0,0 +1,15 @@
+package io.javaoperatorsdk.operator.sample.statefulsetdesiredsanitizer;
+
+public class StatefulSetDesiredSanitizerSpec {
+
+ private String value;
+
+ public String getValue() {
+ return value;
+ }
+
+ public StatefulSetDesiredSanitizerSpec setValue(String value) {
+ this.value = value;
+ return this;
+ }
+}
diff --git a/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/statefulset.yaml b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/statefulset.yaml
new file mode 100644
index 0000000000..f40fbeb607
--- /dev/null
+++ b/operator-framework/src/test/resources/io/javaoperatorsdk/operator/sample/statefulsetdesiredsanitizer/statefulset.yaml
@@ -0,0 +1,35 @@
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: ""
+spec:
+ selector:
+ matchLabels:
+ app: nginx # has to match .spec.template.metadata.labels
+ serviceName: "nginx"
+ replicas: 1
+ minReadySeconds: 10 # by default is 0
+ template:
+ metadata:
+ labels:
+ app: nginx # has to match .spec.selector.matchLabels
+ spec:
+ terminationGracePeriodSeconds: 10
+ containers:
+ - name: nginx
+ image: registry.k8s.io/nginx-slim:0.8
+ ports:
+ - containerPort: 80
+ name: web
+ volumeMounts:
+ - name: www
+ mountPath: /usr/share/nginx/html
+ volumeClaimTemplates:
+ - metadata:
+ name: www
+ spec:
+ accessModes: [ "ReadWriteOnce" ]
+ storageClassName: "my-storage-class"
+ resources:
+ requests:
+ storage: 1Gi
\ No newline at end of file
diff --git a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java
index cc7b15146b..ea1731041f 100644
--- a/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java
+++ b/sample-operators/webpage/src/main/java/io/javaoperatorsdk/operator/sample/dependentresource/ConfigMapDependentResource.java
@@ -47,9 +47,9 @@ protected ConfigMap desired(WebPage webPage, Context context) {
}
@Override
- public ConfigMap update(ConfigMap actual, ConfigMap target, WebPage primary,
+ public ConfigMap update(ConfigMap actual, ConfigMap desired, WebPage primary,
Context context) {
- var res = super.update(actual, target, primary, context);
+ var res = super.update(actual, desired, primary, context);
var ns = actual.getMetadata().getNamespace();
log.info("Restarting pods because HTML has changed in {}",
ns);