Skip to content

feat: configurable SSA per Dependent Resource #2045

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 1 commit into from
Sep 8, 2023
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
@@ -0,0 +1,19 @@
package io.javaoperatorsdk.operator.processing.dependent.kubernetes;

/**
* A replacement for {@link Boolean}, which can't be used in annotations.
*/
public enum BooleanWithUndefined {
TRUE, FALSE, UNDEFINED;

Boolean asBoolean() {
switch (this) {
case TRUE:
return Boolean.TRUE;
case FALSE:
return Boolean.FALSE;
default:
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* namespace is specified then the controller will monitor the namespaces configured for the
* controller.
*
* @return the list of namespaces this controller monitors
* @return the array of namespaces this controller monitors
*/
String[] namespaces() default {Constants.SAME_AS_CONTROLLER};

Expand Down Expand Up @@ -76,4 +76,16 @@
* Creates the resource only if did not exist before, this applies only if SSA is used.
*/
boolean createResourceOnlyIfNotExistingWithSSA() default KubernetesDependentResourceConfig.DEFAULT_CREATE_RESOURCE_ONLY_IF_NOT_EXISTING_WITH_SSA;

/**
* Determines whether to use SSA (Server-Side Apply) for this dependent. If SSA is used, the
* dependent resource will only be created if it did not exist before. Default value is
* {@link BooleanWithUndefined#UNDEFINED}, which specifies that the behavior with respect to SSA
* is inherited from the global configuration.
*
* @return {@code true} if SSA is enabled, {@code false} if SSA is disabled,
* {@link BooleanWithUndefined#UNDEFINED} if the SSA behavior should be inherited from the
* global configuration
*/
BooleanWithUndefined useSSA() default BooleanWithUndefined.UNDEFINED;
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public KubernetesDependentResourceConfig<R> configFrom(KubernetesDependent confi
OnDeleteFilter<? extends HasMetadata> onDeleteFilter = null;
GenericFilter<? extends HasMetadata> genericFilter = null;
ResourceDiscriminator<?, ?> resourceDiscriminator = null;
Boolean useSSA = null;
if (configAnnotation != null) {
if (!Arrays.equals(KubernetesDependent.DEFAULT_NAMESPACES, configAnnotation.namespaces())) {
namespaces = Set.of(configAnnotation.namespaces());
Expand All @@ -58,10 +59,11 @@ public KubernetesDependentResourceConfig<R> configFrom(KubernetesDependent confi
context);
createResourceOnlyIfNotExistingWithSSA =
configAnnotation.createResourceOnlyIfNotExistingWithSSA();
useSSA = configAnnotation.useSSA().asBoolean();
}

return new KubernetesDependentResourceConfig(namespaces, labelSelector, configuredNS,
createResourceOnlyIfNotExistingWithSSA,
resourceDiscriminator, onAddFilter, onUpdateFilter, onDeleteFilter, genericFilter);
resourceDiscriminator, useSSA, onAddFilter, onUpdateFilter, onDeleteFilter, genericFilter);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,10 @@ protected void addMetadata(boolean forMatch, R actualResource, final R target, P
}

private boolean useSSA(Context<P> context) {
return context.getControllerConfiguration().getConfigurationService()
.ssaBasedCreateUpdateMatchForDependentResources();
Optional<Boolean> useSSAConfig =
configuration().flatMap(KubernetesDependentResourceConfig::useSSA);
return useSSAConfig.orElse(context.getControllerConfiguration().getConfigurationService()
.ssaBasedCreateUpdateMatchForDependentResources());
}

@Override
Expand All @@ -206,6 +208,7 @@ public void deleteTargetResource(P primary, R resource, String key, Context<P> c
client.resource(resource).delete();
}

@SuppressWarnings("unused")
protected Resource<R> prepare(R desired, P primary, String actionName) {
log.debug("{} target resource with type: {}, with id: {}",
actionName,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.javaoperatorsdk.operator.processing.dependent.kubernetes;

import java.util.Optional;
import java.util.Set;

import io.javaoperatorsdk.operator.api.reconciler.Constants;
Expand All @@ -20,6 +21,7 @@ public class KubernetesDependentResourceConfig<R> {
private boolean namespacesWereConfigured = false;
private boolean createResourceOnlyIfNotExistingWithSSA;
private ResourceDiscriminator<R, ?> resourceDiscriminator;
private Boolean useSSA;

private OnAddFilter<R> onAddFilter;

Expand All @@ -36,6 +38,7 @@ public KubernetesDependentResourceConfig(Set<String> namespaces,
boolean configuredNS,
boolean createResourceOnlyIfNotExistingWithSSA,
ResourceDiscriminator<R, ?> resourceDiscriminator,
Boolean useSSA,
OnAddFilter<R> onAddFilter,
OnUpdateFilter<R> onUpdateFilter,
OnDeleteFilter<R> onDeleteFilter, GenericFilter<R> genericFilter) {
Expand All @@ -48,12 +51,13 @@ public KubernetesDependentResourceConfig(Set<String> namespaces,
this.onDeleteFilter = onDeleteFilter;
this.genericFilter = genericFilter;
this.resourceDiscriminator = resourceDiscriminator;
this.useSSA = useSSA;
}

public KubernetesDependentResourceConfig(Set<String> namespaces, String labelSelector) {
this(namespaces, labelSelector, true, DEFAULT_CREATE_RESOURCE_ONLY_IF_NOT_EXISTING_WITH_SSA,
null, null, null,
null, null);
null, null, null);
}

public KubernetesDependentResourceConfig<R> setLabelSelector(String labelSelector) {
Expand Down Expand Up @@ -105,4 +109,8 @@ protected void setNamespaces(Set<String> namespaces) {
this.namespaces = namespaces;
}
}

public Optional<Boolean> useSSA() {
return Optional.ofNullable(useSSA);
}
}