From 82dc98a0d97f634974d44fc36ce5ff6aceaa3ee3 Mon Sep 17 00:00:00 2001 From: Ryan Emerson Date: Tue, 22 Jul 2025 11:38:11 +0100 Subject: [PATCH] Document configuration changes that prevent rolling updates Closes #41214 Signed-off-by: Ryan Emerson Signed-off-by: Alexander Schwartz Co-authored-by: Alexander Schwartz Co-authored-by: Alexander Schwartz --- docs/guides/server/update-compatibility.adoc | 62 ++++++++++++++++--- .../org/keycloak/guides/maven/Features.java | 22 +++++-- 2 files changed, 69 insertions(+), 15 deletions(-) diff --git a/docs/guides/server/update-compatibility.adoc b/docs/guides/server/update-compatibility.adoc index 2913be82445..0f17660fe6d 100644 --- a/docs/guides/server/update-compatibility.adoc +++ b/docs/guides/server/update-compatibility.adoc @@ -5,6 +5,7 @@ <@tmpl.guide title="Checking if rolling updates are possible" summary="Execute the update compatibility command to check if {project_name} supports a rolling update for a change in your deployment." +includedOptions="features features-*" > Use the update compatibility command to determine if you can update your deployment with a rolling update strategy when enabling or disabling features or changing the {project_name} version, configurations or providers and themes. @@ -46,15 +47,7 @@ NOTE: If you do not use `--optimized` keep in mind that an `update` command may [WARNING] ==== -The `check` command currently offers only a limited functionality. At the moment, it takes into consideration only the version of {project_name} and the embedded Infinispan to determine if a rolling update is possible. -If those are unchanged, it reports that a rolling update is possible. - -The current version does not yet verify configuration changes and assumes all configuration changes are eligible for a rolling update. -The same applies to changes to custom extensions and themes. - -A good use case when to use this is, for example, when you want to do a rolling update when you change the {project_name} theme or your custom extensions, and only want run recreate update when the version of {project_name} changes which does not yet allow a rolling update. - -While consumers of these commands should know the limitations that exist today, they should not rely on the internal behavior or the structure of the metadata file. +Consumers of these commands should not rely on the internal behavior or the structure of the metadata file. Instead, they should rely only on the exit code of the `check` command to benefit from future enhancements on the internal logic to determine when a rolling update is possible. ==== @@ -143,6 +136,46 @@ m|4 The feature `rolling-updates` is disabled. |=== +== Rolling incompatible changes + +The following configuration changes return a "Rolling Update is not possible" result code. + +=== Features + +==== Recreate always + +The enabling or disabling of the following features requires a recreate update: + +<@showFeaturesRolling ctx.features.updatePolicyShutdown /> + + +==== Recreate on feature version change + +Changing the following features versions triggers a recreate update: + +<@showFeaturesRolling ctx.features.updatePolicyRollingNoUpgrade /> + +=== Configuration options + +Changing the value of one of the following CLI options triggers a recreate update: + +[cols="30%,70%"] +|=== +| Option | Rationale +| `--cache` | The `ispn` and `local` configurations are mutually exclusive, changing from one to another will lead to data loss. +| `--cache-config-file` | Changing the configuration file could result in incompatible cache or transport configurations, resulting in clusters not forming as expected. +| `--cache-stack` | Changing stack will result in the cluster not forming during rolling update and will lead to data loss. +| `--cache-embedded-mtls-enabled` | Enabling/Disabling TLS will result in the cluster not forming during rolling update and will lead to data loss. +| `--cache-remote-host` | Connecting to a new remote cache will cause previously cached data to be lost. +| `--cache-remote-port` | Connecting to a new remote cache will cause previously cached data to be lost. +|=== + +[WARNING] +==== +{project_name} does not verify changes to the content of the cache configuration file provided via `--cache-config-file`. +If you change this file, you need to review and test your changes to ensure that nodes using the new configuration can form a cluster with the nodes running the old configuration. +If a cluster cannot be formed, you should shut down {project_name} running the old configuration first before migrating to the new configuration. +==== [[rolling-updates-for-patch-releases]] == Rolling updates for patch releases @@ -177,3 +210,14 @@ Known limitations: The {project_name} Operator uses the functionality described above to determine if a rolling update is possible. See the <@links.operator id="rolling-updates" /> {section} and the `Auto` strategy for more information. + +<#macro showFeaturesRolling features> +[cols="30%,70%"] +|=== +| Feature | Description + +<#list features as feature> +| [.features-name]#${feature.versionedKey}# | [.features-description]#${feature.description}# + +|=== + diff --git a/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Features.java b/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Features.java index be1dcaa1342..b34e31a19c8 100644 --- a/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Features.java +++ b/docs/maven-plugin/src/main/java/org/keycloak/guides/maven/Features.java @@ -9,12 +9,12 @@ import java.util.stream.Collectors; public class Features { - private List features; + private final List features; public Features() { this.features = Arrays.stream(Profile.Feature.values()) .filter(f -> !f.getType().equals(Profile.Feature.Type.EXPERIMENTAL)) - .map(f -> new Feature(f)) + .map(Feature::new) .sorted(Comparator.comparing(Feature::getName)) .collect(Collectors.toList()); } @@ -35,9 +35,17 @@ public class Features { return features.stream().filter(f -> f.getType().equals(Profile.Feature.Type.PREVIEW)).collect(Collectors.toList()); } - public class Feature { + public List getUpdatePolicyShutdown() { + return features.stream().filter(f -> f.profileFeature.getUpdatePolicy() == Profile.FeatureUpdatePolicy.SHUTDOWN).collect(Collectors.toList()); + } - private Profile.Feature profileFeature; + public List getUpdatePolicyRollingNoUpgrade() { + return features.stream().filter(f -> f.profileFeature.getUpdatePolicy() == Profile.FeatureUpdatePolicy.ROLLING_NO_UPGRADE).collect(Collectors.toList()); + } + + public static class Feature { + + private final Profile.Feature profileFeature; public Feature(Profile.Feature profileFeature) { this.profileFeature = profileFeature; @@ -55,10 +63,12 @@ public class Features { return profileFeature.getVersionedKey(); } + public String getUpdatePolicy() { + return profileFeature.getUpdatePolicy().toString(); + } + private Profile.Feature.Type getType() { return profileFeature.getType(); } - } - }