Deprecate old remote store

Closes #32577

Signed-off-by: Pedro Ruivo <pruivo@redhat.com>
Signed-off-by: Alexander Schwartz <aschwart@redhat.com>
Co-authored-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
Pedro Ruivo 2024-09-04 11:25:51 +01:00 committed by GitHub
parent c4b0fbc105
commit 3274591fe1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 49 additions and 12 deletions

View file

@ -120,7 +120,9 @@ public class Profile {
ORGANIZATION("Organization support within realms", Type.PREVIEW), ORGANIZATION("Organization support within realms", Type.PREVIEW),
PASSKEYS("Passkeys", Type.PREVIEW) PASSKEYS("Passkeys", Type.PREVIEW),
REMOTE_STORE_CROSS_DC("Support for remote-store in embedded Infinispan caches", Type.DEPRECATED)
; ;
private final Type type; private final Type type;

View file

@ -111,14 +111,29 @@ As a consequence of the above changes, the following changes are required to you
. `distributed-cache` definitions provided by a cache configuration file are ignored when the `multi-site` feature is enabled, . `distributed-cache` definitions provided by a cache configuration file are ignored when the `multi-site` feature is enabled,
so you must configure the connection to the external {jdgserver_name} deployment via the `cache-remote-*` command line arguments so you must configure the connection to the external {jdgserver_name} deployment via the `cache-remote-*` command line arguments
or Keycloak CR as outlined in the blueprints. If a `remote-store` configuration is detected in the cache configuration file, or Keycloak CR as outlined in the blueprints. All `remote-store` configurations must be removed from the cache configuration file.
then a warning will be raised in the {project_name} logs.
. Review your current cache configurations in the external {jdgserver_name} and update them with those outlined in the latest version of the {project_name}'s documentation. . Review your current cache configurations in the external {jdgserver_name} and update them with those outlined in the latest version of the {project_name}'s documentation.
. While previous LoadBalancer configurations will continue to work with {project_name}, consider upgrading . While previous LoadBalancer configurations will continue to work with {project_name}, consider upgrading
an existing Route53 configurations to avoid prolonged failover times due to client side DNS caching. an existing Route53 configurations to avoid prolonged failover times due to client side DNS caching.
= Deprecating remote-store in embedded Infinispan caches
In {project_name} versions 24 to 25 to achieve a multi-site setup, a remote store in embedded Infinispan caches was configured.
Manual configurations for the cache XML for multi-site were discouraged as CLI options to configure the caches are available.
With the upgraded multi-site feature in 26, the same CLI options exist, but don't use embedded Infinispan caches anymore.
In the community, remote stores for embedded Infinispan caches were used in some setups to keep user sessions when the {project_name} cluster was shut down or upgraded.
This was never supported, documented or tested.
As a fully supported alternative, the persistent user sessions feature should be used instead.
Due to this, using remote caches in embedded Infinispan caches is now marked as deprecated with the plan to remove it.
As it was never used outside multi-site setups that now achieve this by different means, it might be removed even in a future minor release.
To be able to use the deprecated feature, you need to enable the feature `remote-store-cross-dc` or {project_name} will not start.
There is an experimental feature `remote-cache` which allows leveraging the new multi-site mechanisms to store session related data in an external {jdgserver_name} server also for single site setups.
= Admin Bootstrapping and Recovery = Admin Bootstrapping and Recovery
It used to be difficult to regain access to a {project_name} instance when all admin users were locked out. The process required multiple advanced steps, including direct database access and manual changes. In an effort to improve the user experience, {project_name} now provides multiple ways to bootstrap a new admin account, which can be used to recover from such situations. It used to be difficult to regain access to a {project_name} instance when all admin users were locked out. The process required multiple advanced steps, including direct database access and manual changes. In an effort to improve the user experience, {project_name} now provides multiple ways to bootstrap a new admin account, which can be used to recover from such situations.

View file

@ -298,15 +298,9 @@ public class CacheManagerFactory {
// remove all distributed caches // remove all distributed caches
logger.debug("Removing all distributed caches."); logger.debug("Removing all distributed caches.");
for (String cacheName : CLUSTERED_CACHE_NAMES) { for (String cacheName : CLUSTERED_CACHE_NAMES) {
var remoteStore = builders.get(cacheName) if (hasRemoteStore(builders.get(cacheName))) {
.persistence()
.stores()
.stream()
.filter(RemoteStoreConfigurationBuilder.class::isInstance)
.findFirst();
if (remoteStore.isPresent())
logger.warnf("remote-store configuration detected for cache '%s'. Explicit cache configuration ignored when using '%s' or '%s' Features.", cacheName, Profile.Feature.REMOTE_CACHE.getKey(), Profile.Feature.MULTI_SITE.getKey()); logger.warnf("remote-store configuration detected for cache '%s'. Explicit cache configuration ignored when using '%s' or '%s' Features.", cacheName, Profile.Feature.REMOTE_CACHE.getKey(), Profile.Feature.MULTI_SITE.getKey());
}
builders.remove(cacheName); builders.remove(cacheName);
} }
// Disable JGroups, not required when the data is stored in the Remote Cache. // Disable JGroups, not required when the data is stored in the Remote Cache.
@ -321,6 +315,8 @@ public class CacheManagerFactory {
configureSessionsCaches(builder); configureSessionsCaches(builder);
} }
checkForRemoteStores(builder);
var start = isStartEagerly(); var start = isStartEagerly();
return CompletableFuture.supplyAsync(() -> new DefaultCacheManager(builder, start)); return CompletableFuture.supplyAsync(() -> new DefaultCacheManager(builder, start));
} }
@ -454,6 +450,26 @@ public class CacheManagerFactory {
} }
} }
private static void checkForRemoteStores(ConfigurationBuilderHolder builder) {
if (Profile.isFeatureEnabled(Profile.Feature.REMOTE_STORE_CROSS_DC) && Profile.isFeatureEnabled(Profile.Feature.MULTI_SITE)) {
logger.fatalf("Feature %s is now deprecated.%nFor multi-site (cross-dc) support, enable only %s.",
Profile.Feature.REMOTE_STORE_CROSS_DC.getKey(), Profile.Feature.MULTI_SITE.getKey());
throw new RuntimeException("The features " + Profile.Feature.REMOTE_STORE_CROSS_DC.getKey() + " and " + Profile.Feature.MULTI_SITE.getKey() + " must not be enabled at the same time.");
}
if (Profile.isFeatureEnabled(Profile.Feature.REMOTE_STORE_CROSS_DC) && Profile.isFeatureEnabled(Profile.Feature.REMOTE_CACHE)) {
logger.fatalf("Feature %s is now deprecated.%nFor multi-site (cross-dc) support, enable only %s.",
Profile.Feature.REMOTE_STORE_CROSS_DC.getKey(), Profile.Feature.REMOTE_CACHE.getKey());
throw new RuntimeException("The features " + Profile.Feature.REMOTE_STORE_CROSS_DC.getKey() + " and " + Profile.Feature.REMOTE_CACHE.getKey() + " must not be enabled at the same time.");
}
if (!Profile.isFeatureEnabled(Profile.Feature.REMOTE_STORE_CROSS_DC)) {
if (builder.getNamedConfigurationBuilders().values().stream().anyMatch(CacheManagerFactory::hasRemoteStore)) {
logger.fatalf("Remote stores are not supported for embedded caches as feature %s is not enabled. This feature is disabled by default as it is now deprecated.%nFor keeping user sessions across restarts, use feature %s which is enabled by default.%nFor multi-site (cross-dc) support, enable %s.",
Profile.Feature.REMOTE_STORE_CROSS_DC.getKey(), Profile.Feature.PERSISTENT_USER_SESSIONS.getKey(), Profile.Feature.MULTI_SITE.getKey());
throw new RuntimeException("Remote store is not supported as feature " + Profile.Feature.REMOTE_STORE_CROSS_DC.getKey() + " is not enabled.");
}
}
}
private static void configureSessionsCaches(ConfigurationBuilderHolder builder) { private static void configureSessionsCaches(ConfigurationBuilderHolder builder) {
Stream.of(USER_SESSION_CACHE_NAME, CLIENT_SESSION_CACHE_NAME, OFFLINE_USER_SESSION_CACHE_NAME, OFFLINE_CLIENT_SESSION_CACHE_NAME) Stream.of(USER_SESSION_CACHE_NAME, CLIENT_SESSION_CACHE_NAME, OFFLINE_USER_SESSION_CACHE_NAME, OFFLINE_CLIENT_SESSION_CACHE_NAME)
.forEach(cacheName -> { .forEach(cacheName -> {
@ -487,4 +503,8 @@ public class CacheManagerFactory {
private static String requiredStringProperty(String propertyName) { private static String requiredStringProperty(String propertyName) {
return Configuration.getOptionalKcValue(propertyName).orElseThrow(() -> new RuntimeException("Property " + propertyName + " required but not specified")); return Configuration.getOptionalKcValue(propertyName).orElseThrow(() -> new RuntimeException("Property " + propertyName + " required but not specified"));
} }
private static boolean hasRemoteStore(ConfigurationBuilder builder) {
return builder.persistence().stores().stream().anyMatch(RemoteStoreConfigurationBuilder.class::isInstance);
}
} }