mirror of
https://github.com/keycloak/keycloak.git
synced 2026-01-09 23:12:06 -03:30
Feature flag: rolling-updates
Closes #36840 Signed-off-by: Pedro Ruivo <pruivo@redhat.com>
This commit is contained in:
parent
690b0e4bef
commit
0f91e67b90
@ -131,7 +131,9 @@ public class Profile {
|
||||
|
||||
USER_EVENT_METRICS("Collect metrics based on user events", Type.PREVIEW),
|
||||
|
||||
IPA_TUURA_FEDERATION("IPA-Tuura user federation provider", Type.EXPERIMENTAL)
|
||||
IPA_TUURA_FEDERATION("IPA-Tuura user federation provider", Type.EXPERIMENTAL),
|
||||
|
||||
ROLLING_UPDATES("Rolling Updates", Type.PREVIEW),
|
||||
;
|
||||
|
||||
private final Type type;
|
||||
|
||||
@ -443,6 +443,12 @@ Check the https://kubernetes.io/docs/concepts/services-networking/network-polici
|
||||
|
||||
The Keycloak Operator offers updates strategies to control how the Operator handles changes to the Keycloak CR.
|
||||
|
||||
[CAUTION]
|
||||
====
|
||||
While on preview stage, the feature `rolling-updates` must be enabled.
|
||||
Otherwise, the {project_name} Operator will fail.
|
||||
====
|
||||
|
||||
**Supported Updates Types:**
|
||||
|
||||
Rolling Updates:: Update the StatefulSet in a rolling fashion, minimizing downtime (requires multiple replicas).
|
||||
@ -466,11 +472,14 @@ kind: Keycloak
|
||||
metadata:
|
||||
name: example-kc
|
||||
spec:
|
||||
features:
|
||||
enabled:
|
||||
- rolling-updates # <1>
|
||||
update:
|
||||
strategy: Recreate|<not set> # <1>
|
||||
strategy: Recreate|<not set> # <2>
|
||||
----
|
||||
|
||||
<1> Set the desired update strategy here (Recreate in this example).
|
||||
<1> Enable preview feature `rolling-updates`.
|
||||
<2> Set the desired update strategy here (Recreate in this example).
|
||||
|
||||
[%autowidth]
|
||||
.Possible field values
|
||||
|
||||
@ -9,7 +9,11 @@ preview="true"
|
||||
previewDiscussionLink="https://github.com/keycloak/keycloak/discussions/36785"
|
||||
>
|
||||
|
||||
// TODO Link to discussion?
|
||||
[CAUTION]
|
||||
====
|
||||
While on preview stage, the feature `rolling-updates` must be enabled.
|
||||
Otherwise, the commands will fail.
|
||||
====
|
||||
|
||||
The goal of this tool is to assist with modifying a {project_name} deployment, whether upgrading to a new version, enabling/disabling features, or changing configuration.
|
||||
The outcome will indicate whether a rolling upgrade is possible or if a recreate upgrade is required.
|
||||
@ -124,6 +128,10 @@ m|2
|
||||
m|3
|
||||
|Rolling Upgrade is not possible.
|
||||
The deployment must be shut down before applying the new configuration.
|
||||
|
||||
m|4
|
||||
|Rolling Upgrade is not possible.
|
||||
The feature `rolling-updates` is disabled.
|
||||
|===
|
||||
|
||||
</@tmpl.guide>
|
||||
|
||||
@ -50,6 +50,6 @@ bin/kc.[sh|bat] bootstrap-admin ${parameters}
|
||||
<#macro updatecompatibility parameters>
|
||||
[source,bash]
|
||||
----
|
||||
bin/kc.[sh|bat] update-compatibility ${parameters}
|
||||
bin/kc.[sh|bat] update-compatibility ${parameters} --features=rolling-updates
|
||||
----
|
||||
</#macro>
|
||||
|
||||
@ -2,4 +2,4 @@ ARG IMAGE=keycloak
|
||||
ARG VERSION=latest
|
||||
FROM $IMAGE:$VERSION
|
||||
|
||||
RUN /opt/keycloak/bin/kc.sh build --db=postgres --health-enabled=true
|
||||
RUN /opt/keycloak/bin/kc.sh build --db=postgres --health-enabled=true --features=rolling-updates
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
package org.keycloak.operator.testsuite.integration;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@ -27,10 +28,11 @@ import io.quarkus.test.junit.QuarkusTest;
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.Keycloak;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.KeycloakStatusCondition;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.ValueOrSecret;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.UnsupportedSpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.FeatureSpec;
|
||||
import org.keycloak.operator.crds.v2alpha1.deployment.spec.UpdateSpec;
|
||||
import org.keycloak.operator.upgrade.UpdateStrategy;
|
||||
|
||||
@ -105,11 +107,12 @@ public class UpgradeTest extends BaseOperatorTest {
|
||||
}
|
||||
var updateSpec = new UpdateSpec();
|
||||
updateSpec.setStrategy(updateStrategy);
|
||||
|
||||
if (kc.getSpec().getUnsupported() == null) {
|
||||
kc.getSpec().setUnsupported(new UnsupportedSpec());
|
||||
}
|
||||
kc.getSpec().setUpdateSpec(updateSpec);
|
||||
|
||||
if (kc.getSpec().getFeatureSpec() == null) {
|
||||
kc.getSpec().setFeatureSpec(new FeatureSpec());
|
||||
}
|
||||
kc.getSpec().getFeatureSpec().setEnabledFeatures(List.of(Profile.Feature.ROLLING_UPDATES.getKey()));
|
||||
return kc;
|
||||
}
|
||||
|
||||
|
||||
@ -80,4 +80,8 @@ public abstract class AbstractUpdatesCommand extends AbstractCommand implements
|
||||
printError("Warning! This command is preview and is not recommended for use in production. It may change or be removed at a future release.");
|
||||
}
|
||||
|
||||
void printFeatureDisabled() {
|
||||
printError("Unable to use this command. The preview feature 'rolling-updates' is not enabled.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -20,7 +20,9 @@ package org.keycloak.quarkus.runtime.cli.command;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.quarkus.runtime.cli.PropertyException;
|
||||
import org.keycloak.quarkus.runtime.compatibility.CompatibilityResult;
|
||||
import org.keycloak.quarkus.runtime.compatibility.ServerInfo;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
import picocli.CommandLine;
|
||||
@ -41,6 +43,11 @@ public class UpdateCompatibilityCheck extends AbstractUpdatesCommand {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!Profile.isFeatureEnabled(Profile.Feature.ROLLING_UPDATES)) {
|
||||
printFeatureDisabled();
|
||||
picocli.exit(CompatibilityResult.FEATURE_DISABLED);
|
||||
return;
|
||||
}
|
||||
printPreviewWarning();
|
||||
validateConfig();
|
||||
var info = readServerInfo();
|
||||
|
||||
@ -21,7 +21,9 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.quarkus.runtime.cli.PropertyException;
|
||||
import org.keycloak.quarkus.runtime.compatibility.CompatibilityResult;
|
||||
import org.keycloak.quarkus.runtime.compatibility.ServerInfo;
|
||||
import org.keycloak.util.JsonSerialization;
|
||||
import picocli.CommandLine;
|
||||
@ -41,6 +43,11 @@ public class UpdateCompatibilityMetadata extends AbstractUpdatesCommand {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!Profile.isFeatureEnabled(Profile.Feature.ROLLING_UPDATES)) {
|
||||
printFeatureDisabled();
|
||||
picocli.exit(CompatibilityResult.FEATURE_DISABLED);
|
||||
return;
|
||||
}
|
||||
printPreviewWarning();
|
||||
validateConfig();
|
||||
var info = compatibilityManager.current();
|
||||
|
||||
@ -28,7 +28,11 @@ import java.util.Optional;
|
||||
public interface CompatibilityResult {
|
||||
|
||||
int ROLLING_UPGRADE_EXIT_CODE = 0;
|
||||
int RECREATE_UPGRADE_EXIT_CODE = 4;
|
||||
// see picocli.CommandLine.ExitCode
|
||||
// 1 -> software error
|
||||
// 2 -> usage error
|
||||
int RECREATE_UPGRADE_EXIT_CODE = 3;
|
||||
int FEATURE_DISABLED = 4;
|
||||
|
||||
/**
|
||||
* The compatible {@link CompatibilityResult} implementation
|
||||
|
||||
@ -41,6 +41,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
@RawDistOnly(reason = "Requires creating JSON file to be available between containers")
|
||||
public class UpdateCommandDistTest {
|
||||
|
||||
private static final String ENABLE_FEATURE = "--features=rolling-updates";
|
||||
|
||||
@Test
|
||||
@Launch({UpdateCompatibility.NAME, UpdateCompatibilityMetadata.NAME})
|
||||
public void testFeatureNotEnabled(CLIResult cliResult) {
|
||||
cliResult.assertError("Unable to use this command. The preview feature 'rolling-updates' is not enabled.");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Launch({UpdateCompatibility.NAME})
|
||||
public void testMissingSubCommand(CLIResult cliResult) {
|
||||
@ -48,13 +56,13 @@ public class UpdateCommandDistTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Launch({UpdateCompatibility.NAME, UpdateCompatibilityMetadata.NAME})
|
||||
@Launch({UpdateCompatibility.NAME, UpdateCompatibilityMetadata.NAME, ENABLE_FEATURE})
|
||||
public void testMissingOptionOnSave(CLIResult cliResult) {
|
||||
cliResult.assertNoMessage("Missing required argument");
|
||||
}
|
||||
|
||||
@Test
|
||||
@Launch({UpdateCompatibility.NAME, UpdateCompatibilityCheck.NAME})
|
||||
@Launch({UpdateCompatibility.NAME, UpdateCompatibilityCheck.NAME, ENABLE_FEATURE})
|
||||
public void testMissingOptionOnCheck(CLIResult cliResult) {
|
||||
cliResult.assertError("Missing required argument: " + UpdateCompatibilityCheck.INPUT_OPTION_NAME);
|
||||
}
|
||||
@ -62,7 +70,7 @@ public class UpdateCommandDistTest {
|
||||
@Test
|
||||
public void testCompatible(KeycloakDistribution distribution) throws IOException {
|
||||
var jsonFile = createTempFile("compatible");
|
||||
var result = distribution.run(UpdateCompatibility.NAME, UpdateCompatibilityMetadata.NAME, UpdateCompatibilityMetadata.OUTPUT_OPTION_NAME, jsonFile.getAbsolutePath());
|
||||
var result = distribution.run(UpdateCompatibility.NAME, UpdateCompatibilityMetadata.NAME, UpdateCompatibilityMetadata.OUTPUT_OPTION_NAME, jsonFile.getAbsolutePath(), ENABLE_FEATURE);
|
||||
result.assertMessage("Metadata:");
|
||||
assertEquals(0, result.exitCode());
|
||||
|
||||
@ -70,7 +78,7 @@ public class UpdateCommandDistTest {
|
||||
assertEquals(Version.VERSION, info.getVersions().get(CompatibilityManagerImpl.KEYCLOAK_VERSION_KEY));
|
||||
assertEquals(org.infinispan.commons.util.Version.getVersion(), info.getVersions().get(CompatibilityManagerImpl.INFINISPAN_VERSION_KEY));
|
||||
|
||||
result = distribution.run(UpdateCompatibility.NAME, UpdateCompatibilityCheck.NAME, UpdateCompatibilityCheck.INPUT_OPTION_NAME, jsonFile.getAbsolutePath());
|
||||
result = distribution.run(UpdateCompatibility.NAME, UpdateCompatibilityCheck.NAME, UpdateCompatibilityCheck.INPUT_OPTION_NAME, jsonFile.getAbsolutePath(), ENABLE_FEATURE);
|
||||
result.assertMessage("[OK] Rolling Upgrade is available.");
|
||||
result.assertNoError("Rolling Upgrade is not available.");
|
||||
}
|
||||
@ -85,7 +93,7 @@ public class UpdateCommandDistTest {
|
||||
CompatibilityManagerImpl.INFINISPAN_VERSION_KEY, org.infinispan.commons.util.Version.getVersion()));
|
||||
JsonSerialization.mapper.writeValue(jsonFile, info);
|
||||
|
||||
var result = distribution.run(UpdateCompatibility.NAME, UpdateCompatibilityCheck.NAME, UpdateCompatibilityCheck.INPUT_OPTION_NAME, jsonFile.getAbsolutePath());
|
||||
var result = distribution.run(UpdateCompatibility.NAME, UpdateCompatibilityCheck.NAME, UpdateCompatibilityCheck.INPUT_OPTION_NAME, jsonFile.getAbsolutePath(), ENABLE_FEATURE);
|
||||
result.assertError("[Versions] Rolling Upgrade is not available. 'keycloak' is incompatible: Old=0.0.0.Final, New=%s".formatted(Version.VERSION));
|
||||
|
||||
// incompatible infinispan version
|
||||
@ -94,7 +102,7 @@ public class UpdateCommandDistTest {
|
||||
CompatibilityManagerImpl.INFINISPAN_VERSION_KEY, "0.0.0.Final"));
|
||||
JsonSerialization.mapper.writeValue(jsonFile, info);
|
||||
|
||||
result = distribution.run(UpdateCompatibility.NAME, UpdateCompatibilityCheck.NAME, UpdateCompatibilityCheck.INPUT_OPTION_NAME, jsonFile.getAbsolutePath());
|
||||
result = distribution.run(UpdateCompatibility.NAME, UpdateCompatibilityCheck.NAME, UpdateCompatibilityCheck.INPUT_OPTION_NAME, jsonFile.getAbsolutePath(), ENABLE_FEATURE);
|
||||
result.assertError("[Versions] Rolling Upgrade is not available. 'infinispan' is incompatible: Old=0.0.0.Final, New=%s".formatted(org.infinispan.commons.util.Version.getVersion()));
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user