mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 15:02:05 -03:30
Rename operator strategy options
Closes #37090 Signed-off-by: Pedro Ruivo <pruivo@redhat.com>
This commit is contained in:
parent
66a7151bb5
commit
81c65c8174
@ -450,7 +450,6 @@ Otherwise, the {project_name} Operator will fail.
|
||||
====
|
||||
|
||||
**Supported Updates Types:**
|
||||
|
||||
Rolling Updates:: Update the StatefulSet in a rolling fashion, minimizing downtime (requires multiple replicas).
|
||||
Recreate Updates:: Scale down the StatefulSet before applying updates, causing temporary downtime.
|
||||
|
||||
@ -458,13 +457,6 @@ Recreate Updates:: Scale down the StatefulSet before applying updates, causing t
|
||||
|
||||
The update strategy is specified within the `spec` section of the Keycloak CR YAML definition.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
During this preview stage, the update strategy defaults to mimicking Keycloak 26.1 or older behavior:
|
||||
When the Keycloak CR's image field changes, the Operator scales down the StatefulSet before applying the new image, resulting in downtime.
|
||||
Any configuration change will be a rolling update.
|
||||
====
|
||||
|
||||
[source,yaml]
|
||||
----
|
||||
apiVersion: k8s.keycloak.org/v2alpha1
|
||||
@ -476,7 +468,7 @@ spec:
|
||||
enabled:
|
||||
- rolling-updates # <1>
|
||||
update:
|
||||
strategy: Recreate|<not set> # <2>
|
||||
strategy: RecreateOnImageChange|ForceRecreate|Auto # <2>
|
||||
----
|
||||
<1> Enable preview feature `rolling-updates`.
|
||||
<2> Set the desired update strategy here (Recreate in this example).
|
||||
@ -486,12 +478,12 @@ spec:
|
||||
|===
|
||||
|Value |Downtime? |Description
|
||||
|
||||
|`<not set>` (default)
|
||||
|`RecreateOnImageChange` (default)
|
||||
|On image name or tag change
|
||||
|Mimics Keycloak 26.1 or older behavior.
|
||||
When the image field changes, the StatefulSet is scaled down before applying the new image.
|
||||
|
||||
|`Recreate`
|
||||
|`ForceRecreate`
|
||||
|On any configuration or image change
|
||||
|The StatefulSet is scaled down before applying the new configuration or image.
|
||||
|
||||
|
||||
@ -17,10 +17,9 @@
|
||||
|
||||
package org.keycloak.operator.crds.v2alpha1.deployment.spec;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
|
||||
import io.fabric8.generator.annotation.Default;
|
||||
import io.sundr.builder.annotations.Buildable;
|
||||
import org.keycloak.operator.crds.v2alpha1.CRDUtils;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
|
||||
@ -31,7 +30,12 @@ import org.keycloak.operator.upgrade.UpdateStrategy;
|
||||
@Buildable(editableEnabled = false, builderPackage = "io.fabric8.kubernetes.api.builder")
|
||||
public class UpdateSpec {
|
||||
|
||||
// those are the default, keep them in sync.
|
||||
private static final UpdateStrategy DEFAULT = UpdateStrategy.RECREATE_ON_IMAGE_CHANGE;
|
||||
private static final String DEFAULT_JSON = "RecreateOnImageChange";
|
||||
|
||||
@JsonPropertyDescription("Sets the upgrade strategy to use.")
|
||||
@Default(DEFAULT_JSON)
|
||||
private UpdateStrategy strategy;
|
||||
|
||||
public UpdateStrategy getStrategy() {
|
||||
@ -42,9 +46,10 @@ public class UpdateSpec {
|
||||
this.strategy = strategy;
|
||||
}
|
||||
|
||||
public static Optional<UpdateStrategy> findUpdateStrategy(Keycloak keycloak) {
|
||||
public static UpdateStrategy getUpdateStrategy(Keycloak keycloak) {
|
||||
return CRDUtils.keycloakSpecOf(keycloak)
|
||||
.map(KeycloakSpec::getUpdateSpec)
|
||||
.map(UpdateSpec::getStrategy);
|
||||
.map(UpdateSpec::getStrategy)
|
||||
.orElse(DEFAULT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,9 +21,14 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
|
||||
|
||||
public enum UpdateStrategy {
|
||||
|
||||
@JsonPropertyDescription("Shutdown the Keycloak cluster when the image changes.")
|
||||
@JsonProperty("RecreateOnImageChange")
|
||||
RECREATE_ON_IMAGE_CHANGE,
|
||||
|
||||
@JsonPropertyDescription("Shutdown the Keycloak cluster before applying the new changes.")
|
||||
@JsonProperty("Recreate")
|
||||
RECREATE,
|
||||
@JsonProperty("ForceRecreate")
|
||||
FORCE_RECREATE,
|
||||
|
||||
@JsonPropertyDescription("Automatically detects if the Keycloak CR changes requires a rolling or recreate update.")
|
||||
@JsonProperty("Auto")
|
||||
|
||||
@ -23,7 +23,7 @@ import org.keycloak.operator.controllers.KeycloakDeploymentDependentResource;
|
||||
import org.keycloak.operator.controllers.KeycloakUpdateJobDependentResource;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.UpdateSpec;
|
||||
import org.keycloak.operator.upgrade.impl.AlwaysRecreateUpgradeLogic;
|
||||
import org.keycloak.operator.upgrade.impl.ForceRecreateUpgradeLogic;
|
||||
import org.keycloak.operator.upgrade.impl.AutoUpgradeLogic;
|
||||
import org.keycloak.operator.upgrade.impl.RecreateOnImageChangeUpgradeLogic;
|
||||
|
||||
@ -33,14 +33,11 @@ import org.keycloak.operator.upgrade.impl.RecreateOnImageChangeUpgradeLogic;
|
||||
@ApplicationScoped
|
||||
public class UpgradeLogicFactory {
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
public UpgradeLogic create(Keycloak keycloak, Context<Keycloak> context, KeycloakDeploymentDependentResource dependentResource, KeycloakUpdateJobDependentResource updateJobDependentResource) {
|
||||
var strategy = UpdateSpec.findUpdateStrategy(keycloak);
|
||||
if (strategy.isEmpty()) {
|
||||
return new RecreateOnImageChangeUpgradeLogic(context, keycloak, dependentResource);
|
||||
}
|
||||
return switch (strategy.get()) {
|
||||
case RECREATE -> new AlwaysRecreateUpgradeLogic(context, keycloak, dependentResource);
|
||||
var strategy = UpdateSpec.getUpdateStrategy(keycloak);
|
||||
return switch (strategy) {
|
||||
case RECREATE_ON_IMAGE_CHANGE -> new RecreateOnImageChangeUpgradeLogic(context, keycloak, dependentResource);
|
||||
case FORCE_RECREATE -> new ForceRecreateUpgradeLogic(context, keycloak, dependentResource);
|
||||
case AUTO -> new AutoUpgradeLogic(context, keycloak, dependentResource, updateJobDependentResource);
|
||||
};
|
||||
}
|
||||
|
||||
@ -30,9 +30,9 @@ import org.keycloak.operator.upgrade.UpgradeType;
|
||||
* An {@link UpgradeLogic} implementation that forces a {@link UpgradeType#RECREATE} on every configuration or image
|
||||
* change.
|
||||
*/
|
||||
public class AlwaysRecreateUpgradeLogic extends BaseUpgradeLogic {
|
||||
public class ForceRecreateUpgradeLogic extends BaseUpgradeLogic {
|
||||
|
||||
public AlwaysRecreateUpgradeLogic(Context<Keycloak> context, Keycloak keycloak, KeycloakDeploymentDependentResource statefulSetResource) {
|
||||
public ForceRecreateUpgradeLogic(Context<Keycloak> context, Keycloak keycloak, KeycloakDeploymentDependentResource statefulSetResource) {
|
||||
super(context, keycloak, statefulSetResource);
|
||||
}
|
||||
|
||||
@ -34,11 +34,8 @@ import org.keycloak.operator.upgrade.UpgradeType;
|
||||
* Implements Keycloak 26.0 logic.
|
||||
* <p>
|
||||
* It uses a {@link UpgradeType#RECREATE} if the image changes; otherwise uses {@link UpgradeType#ROLLING}.
|
||||
*
|
||||
* @deprecated To be removed when the new zero-downtime feature is completed.
|
||||
*/
|
||||
@SuppressWarnings("ALL")
|
||||
@Deprecated(forRemoval = true)
|
||||
public class RecreateOnImageChangeUpgradeLogic extends BaseUpgradeLogic {
|
||||
|
||||
public RecreateOnImageChangeUpgradeLogic(Context<Keycloak> context, Keycloak keycloak, KeycloakDeploymentDependentResource dependentResource) {
|
||||
|
||||
@ -23,7 +23,6 @@ import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import io.fabric8.kubernetes.api.model.batch.v1.Job;
|
||||
import io.fabric8.kubernetes.api.model.batch.v1.JobStatus;
|
||||
@ -32,7 +31,7 @@ import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.operator.controllers.KeycloakUpdateJobDependentResource;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
|
||||
@ -55,16 +54,8 @@ import static org.keycloak.operator.testsuite.utils.K8sUtils.deployKeycloak;
|
||||
@QuarkusTest
|
||||
public class UpgradeTest extends BaseOperatorTest {
|
||||
|
||||
private static Stream<UpdateStrategy> upgradeStrategy() {
|
||||
return Stream.of(
|
||||
null,
|
||||
UpdateStrategy.RECREATE,
|
||||
UpdateStrategy.AUTO
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "testImageChange-{0}")
|
||||
@MethodSource("upgradeStrategy")
|
||||
@EnumSource(UpdateStrategy.class)
|
||||
public void testImageChange(UpdateStrategy updateStrategy) throws InterruptedException {
|
||||
var kc = createInitialDeployment(updateStrategy);
|
||||
deployKeycloak(k8sclient, kc, true);
|
||||
@ -97,7 +88,7 @@ public class UpgradeTest extends BaseOperatorTest {
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "testCacheMaxCount-{0}")
|
||||
@MethodSource("upgradeStrategy")
|
||||
@EnumSource(UpdateStrategy.class)
|
||||
public void testCacheMaxCount(UpdateStrategy updateStrategy) throws InterruptedException {
|
||||
var kc = createInitialDeployment(updateStrategy);
|
||||
deployKeycloak(k8sclient, kc, true);
|
||||
@ -105,7 +96,7 @@ public class UpgradeTest extends BaseOperatorTest {
|
||||
// changing the local cache max-count should never use the recreate upgrade type
|
||||
// except if forced by the Keycloak CR.
|
||||
kc.getSpec().getAdditionalOptions().add(new ValueOrSecret("cache-embedded-authorization-max-count", "10"));
|
||||
var upgradeCondition = updateStrategy == UpdateStrategy.RECREATE ?
|
||||
var upgradeCondition = updateStrategy == UpdateStrategy.FORCE_RECREATE ?
|
||||
eventuallyRecreateUpgradeStatus(k8sclient, kc) :
|
||||
eventuallyRollingUpgradeStatus(k8sclient, kc);
|
||||
|
||||
@ -119,7 +110,7 @@ public class UpgradeTest extends BaseOperatorTest {
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "testOptimizedImage-{0}")
|
||||
@MethodSource("upgradeStrategy")
|
||||
@EnumSource(UpdateStrategy.class)
|
||||
@EnabledIfSystemProperty(named = OPERATOR_CUSTOM_IMAGE, matches = ".+")
|
||||
public void testOptimizedImage(UpdateStrategy updateStrategy) throws InterruptedException {
|
||||
// In GHA, the custom image is an optimized image of the base image.
|
||||
|
||||
@ -262,7 +262,7 @@ public class CRSerializationTest {
|
||||
assertNotNull(updateSpec);
|
||||
var upgradeStrategy = updateSpec.getStrategy();
|
||||
assertNotNull(upgradeStrategy);
|
||||
assertEquals(UpdateStrategy.RECREATE, upgradeStrategy);
|
||||
assertEquals(UpdateStrategy.FORCE_RECREATE, upgradeStrategy);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -124,7 +124,7 @@ spec:
|
||||
service:
|
||||
secret: else
|
||||
update:
|
||||
strategy: Recreate
|
||||
strategy: ForceRecreate
|
||||
unsupported:
|
||||
podTemplate:
|
||||
metadata:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user