Skip to content

Commit

Permalink
Allow Quarkus configuration to mix different storage providers
Browse files Browse the repository at this point in the history
Closes #13312
  • Loading branch information
ahus1 authored and hmlnarik committed Jul 26, 2022
1 parent 4e83b9b commit 67e2f34
Show file tree
Hide file tree
Showing 9 changed files with 361 additions and 68 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,7 @@ jobs:
- name: Run Quarkus Storage Tests
run: |
./mvnw clean install -nsu -B -f quarkus/tests/pom.xml -Ptest-database -Dtest=PostgreSQLDistTest,DatabaseOptionsDistTest,JPAStoreDistTest,HotRodStoreDistTest | misc/log/trimmer.sh
./mvnw clean install -nsu -B -f quarkus/tests/pom.xml -Ptest-database -Dtest=PostgreSQLDistTest,DatabaseOptionsDistTest,JPAStoreDistTest,HotRodStoreDistTest,MixedStoreDistTest | misc/log/trimmer.sh
TEST_RESULT=${PIPESTATUS[0]}
find . -path '*/target/surefire-reports/*.xml' | zip -q reports-quarkus-tests.zip -@
exit $TEST_RESULT
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,14 @@ private StoragePropertyMappers(){}
public static PropertyMapper[] getMappers() {
return new PropertyMapper[] {
fromOption(StorageOptions.STORAGE)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_PROVIDER)
.to("kc.spi-map-storage-provider")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_EVENT_STORE)
fromOption(StorageOptions.STORAGE_EVENT_STORE_PROVIDER)
.mapFrom("storage")
.to("kc.spi-events-store-provider")
.transformer(StoragePropertyMappers::getAreaStorage)
Expand All @@ -55,7 +58,7 @@ public static PropertyMapper[] getMappers() {
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_REALM)
fromOption(StorageOptions.STORAGE_REALM_PROVIDER)
.to("kc.spi-realm-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage)
Expand All @@ -67,7 +70,7 @@ public static PropertyMapper[] getMappers() {
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_CLIENT)
fromOption(StorageOptions.STORAGE_CLIENT_PROVIDER)
.to("kc.spi-client-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage)
Expand All @@ -79,7 +82,7 @@ public static PropertyMapper[] getMappers() {
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_CLIENT_SCOPE)
fromOption(StorageOptions.STORAGE_CLIENT_SCOPE_PROVIDER)
.to("kc.spi-client-scope-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage)
Expand All @@ -91,7 +94,7 @@ public static PropertyMapper[] getMappers() {
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_GROUP)
fromOption(StorageOptions.STORAGE_GROUP_PROVIDER)
.to("kc.spi-group-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage)
Expand All @@ -103,7 +106,7 @@ public static PropertyMapper[] getMappers() {
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_ROLE)
fromOption(StorageOptions.STORAGE_ROLE_PROVIDER)
.to("kc.spi-role-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage)
Expand All @@ -115,7 +118,7 @@ public static PropertyMapper[] getMappers() {
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_USER)
fromOption(StorageOptions.STORAGE_USER_PROVIDER)
.to("kc.spi-user-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage)
Expand All @@ -127,13 +130,13 @@ public static PropertyMapper[] getMappers() {
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_DEPLOYMENT_STATE)
fromOption(StorageOptions.STORAGE_DEPLOYMENT_STATE_PROVIDER)
.to("kc.spi-deployment-state-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_AUTH_SESSION)
fromOption(StorageOptions.STORAGE_AUTH_SESSION_PROVIDER)
.to("kc.spi-authentication-sessions-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getCacheStorage)
Expand All @@ -145,7 +148,7 @@ public static PropertyMapper[] getMappers() {
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_USER_SESSION)
fromOption(StorageOptions.STORAGE_USER_SESSION_PROVIDER)
.to("kc.spi-user-sessions-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getCacheStorage)
Expand All @@ -157,7 +160,7 @@ public static PropertyMapper[] getMappers() {
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_LOGIN_FAILURE)
fromOption(StorageOptions.STORAGE_LOGIN_FAILURE_PROVIDER)
.to("kc.spi-login-failure-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getCacheStorage)
Expand All @@ -175,13 +178,19 @@ public static PropertyMapper[] getMappers() {
.transformer(StoragePropertyMappers::getUserSessionPersisterStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_AUTHORIZATION_PERSISTER)
fromOption(StorageOptions.STORAGE_AUTHORIZATION_PROVIDER)
.to("kc.spi-authorization-persister-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getAreaStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_ACTION_TOKEN)
fromOption(StorageOptions.STORAGE_AUTHORIZATION_STORE)
.to("kc.spi-authorization-persister-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_ACTION_TOKEN_PROVIDER)
.to("kc.spi-action-token-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getCacheStorage)
Expand Down Expand Up @@ -217,7 +226,7 @@ public static PropertyMapper[] getMappers() {
.transformer(StoragePropertyMappers::isCacheAreaEnabledForStorage)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(),
fromOption(StorageOptions.STORAGE_SINGLE_USE_OBJECT)
fromOption(StorageOptions.STORAGE_SINGLE_USE_OBJECT_PROVIDER)
.to("kc.spi-single-use-object-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::getCacheStorage)
Expand All @@ -229,10 +238,10 @@ public static PropertyMapper[] getMappers() {
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_PUBLIC_KEY_STORE)
fromOption(StorageOptions.STORAGE_PUBLIC_KEY_STORAGE_STORE)
.to("kc.spi-public-key-storage-map-storage-provider")
.mapFrom("storage")
.transformer(StoragePropertyMappers::resolveMapStorageProvider)
.transformer(StoragePropertyMappers::resolveMapStorageProviderPublicKeyStorage)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_EXCEPTION_CONVERTER)
Expand All @@ -241,19 +250,19 @@ public static PropertyMapper[] getMappers() {
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(),
fromOption(StorageOptions.STORAGE_CACHE_CLEAR_REALM)
fromOption(StorageOptions.STORAGE_ADMIN_CACHE_CLEAR_REALM)
.to("kc.spi-admin-realm-restapi-extension-clear-realm-cache-enabled")
.mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(),
fromOption(StorageOptions.STORAGE_CACHE_CLEAR_USER)
fromOption(StorageOptions.STORAGE_ADMIN_CACHE_CLEAR_USER)
.to("kc.spi-admin-realm-restapi-extension-clear-user-cache-enabled")
.mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
.build(),
fromOption(StorageOptions.STORAGE_CACHE_CLEAR_KEYS)
fromOption(StorageOptions.STORAGE_ADMIN_CACHE_CLEAR_KEYS)
.to("kc.spi-admin-realm-restapi-extension-clear-keys-cache-enabled")
.mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
Expand All @@ -265,7 +274,7 @@ public static PropertyMapper[] getMappers() {
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
.paramLabel("type")
.build(),
fromOption(StorageOptions.STORAGE_USER_STORAGE)
fromOption(StorageOptions.STORAGE_ADMIN_USER_STORAGE)
.to("kc.spi-admin-realm-restapi-extension-user-storage-enabled")
.mapFrom("storage")
.transformer(StoragePropertyMappers::isLegacyStoreEnabled)
Expand Down Expand Up @@ -343,6 +352,20 @@ private static Optional<String> resolveMapStorageProvider(Optional<String> value
return value;
}

private static Optional<String> resolveMapStorageProviderPublicKeyStorage(Optional<String> value, ConfigSourceInterceptorContext context) {
try {
if (value.isPresent()) {
// there is only one public key storage provider available
return of(StorageType.chm.getProvider());
}
} catch (IllegalArgumentException iae) {
throw new IllegalArgumentException("Invalid storage provider: " + value.orElse(null), iae);
}

return value;
}


private static Optional<String> isCacheAreaEnabledForStorage(Optional<String> storage, ConfigSourceInterceptorContext context) {
return of(storage.isEmpty() ? Boolean.TRUE.toString() : Boolean.FALSE.toString());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.keycloak.quarkus.runtime.configuration.test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource.CLI_ARGS;

Expand Down Expand Up @@ -485,6 +486,30 @@ public void testLogHandlerConfig() {
assertEquals("true", config4.getConfigValue("quarkus.log.handler.gelf.enabled").getValue());
}

@Test
public void testStorageMixedStorageOptions() {
System.setProperty(CLI_ARGS, "--storage=jpa" + ARG_SEPARATOR + "--storage-realm=chm");
SmallRyeConfig config = createConfig();
assertEquals("jpa", config.getConfigValue("kc.storage").getValue());
assertNull(config.getConfigValue("kc.spi-map-storage-provider").getValue());
assertEquals("map", config.getConfigValue("kc.spi-realm-provider").getValue());
assertEquals("concurrenthashmap", config.getConfigValue("kc.spi-realm-map-storage-provider").getValue());
assertEquals("map", config.getConfigValue("kc.spi-user-provider").getValue());
assertEquals("jpa", config.getConfigValue("kc.spi-user-map-storage-provider").getValue());
}

@Test
public void testStoragePureJpa() {
System.setProperty(CLI_ARGS, "--storage=jpa");
SmallRyeConfig config = createConfig();
assertEquals("jpa", config.getConfigValue("kc.storage").getValue());
assertNull(config.getConfigValue("kc.spi-map-storage-provider").getValue());
assertEquals("map", config.getConfigValue("kc.spi-realm-provider").getValue());
assertEquals("jpa", config.getConfigValue("kc.spi-realm-map-storage-provider").getValue());
assertEquals("map", config.getConfigValue("kc.spi-user-provider").getValue());
assertEquals("jpa", config.getConfigValue("kc.spi-user-map-storage-provider").getValue());
}

@Test
public void testOptionValueWithEqualSign() {
System.setProperty(CLI_ARGS, "--db=postgres" + ARG_SEPARATOR + "--db-password=my_secret=");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.keycloak.it.storage.map;

import io.quarkus.test.junit.main.Launch;
import io.quarkus.test.junit.main.LaunchResult;
import org.junit.jupiter.api.Test;
import org.keycloak.it.junit5.extension.CLIResult;
import org.keycloak.it.junit5.extension.DistributionTest;
import org.keycloak.it.junit5.extension.RawDistOnly;
import org.keycloak.it.junit5.extension.WithDatabase;
import org.keycloak.it.utils.RawDistRootPath;

import java.io.File;
import java.nio.file.Paths;

import static org.junit.jupiter.api.Assertions.assertTrue;

@DistributionTest
@RawDistOnly(reason = "Containers are immutable")
@WithDatabase(alias = "postgres", buildOptions = {"storage=jpa", "storage-realm=chm"})
public class MixedStoreDistTest {

@Test
@Launch({ "start", "--http-enabled=true", "--hostname-strict=false" })
void testStartUsingMixedStorage(LaunchResult result, RawDistRootPath distRoot) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertStarted();
File chmRealmsFile = Paths.get(distRoot.getDistRootPath().toString(), "data","chm", "map-realms.json").toFile();
assertTrue(chmRealmsFile.isFile(), "File for realms does not exist!");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,32 @@ Cache:

Storage (Experimental):

--storage <type> Experimental: Sets a storage mechanism. Possible values are: jpa, chm, hotrod.
--storage <type> Experimental: Sets the default storage mechanism for all areas. Possible
values are: jpa, chm, hotrod.
--storage-action-token <type>
Experimental: Sets a storage mechanism for action tokens. Possible values are:
jpa, chm, hotrod.
--storage-auth-session <type>
Experimental: Sets a storage mechanism for authentication sessions. Possible
values are: jpa, chm, hotrod.
--storage-authorization <type>
Experimental: Sets a storage mechanism for authorizations. Possible values
are: jpa, chm, hotrod.
--storage-client <type>
Experimental: Sets a storage mechanism for clients. Possible values are: jpa,
chm, hotrod.
--storage-client-scope <type>
Experimental: Sets a storage mechanism for client scopes. Possible values are:
jpa, chm, hotrod.
--storage-event-admin <type>
Experimental: Sets a storage mechanism for admin events. Possible values are:
jpa, chm, hotrod.
--storage-event-auth <type>
Experimental: Sets a storage mechanism for authentication and authorization
events. Possible values are: jpa, chm, hotrod.
--storage-group <type>
Experimental: Sets a storage mechanism for groups. Possible values are: jpa,
chm, hotrod.
--storage-hotrod-cache-configure <true|false>
Experimental: When set to true, Keycloak will create and configure Infinispan
caches on startup. Default: true.
Expand All @@ -44,6 +69,24 @@ Storage (Experimental):
Experimental: Sets the port of the Infinispan server.
--storage-hotrod-username <username>
Experimental: Sets the username of the Infinispan user.
--storage-login-failure <type>
Experimental: Sets a storage mechanism for login failures. Possible values
are: jpa, chm, hotrod.
--storage-realm <type>
Experimental: Sets a storage mechanism for realms. Possible values are: jpa,
chm, hotrod.
--storage-role <type>
Experimental: Sets a storage mechanism for roles. Possible values are: jpa,
chm, hotrod.
--storage-single-use-object <type>
Experimental: Sets a storage mechanism for single use objects. Possible values
are: jpa, chm, hotrod.
--storage-user <type>
Experimental: Sets a storage mechanism for users. Possible values are: jpa,
chm, hotrod.
--storage-user-session <type>
Experimental: Sets a storage mechanism for user and client sessions. Possible
values are: jpa, chm, hotrod.

Database:

Expand Down

0 comments on commit 67e2f34

Please sign in to comment.