Support for non-XA databases (#20141)
This commit is contained in:
parent
b6147141f3
commit
c17fcd49c8
12 changed files with 48 additions and 145 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -133,7 +133,7 @@ jobs:
|
|||
declare -A PARAMS
|
||||
PARAMS["zip"]=""
|
||||
PARAMS["container"]="-Dkc.quarkus.tests.dist=docker"
|
||||
PARAMS["storage"]="-Ptest-database -Dtest=PostgreSQLDistTest,MariaDBDistTest#testSuccessful,MySQLDistTest#testSuccessful,DatabaseOptionsDistTest,JPAStoreDistTest,HotRodStoreDistTest,MixedStoreDistTest"
|
||||
PARAMS["storage"]="-Ptest-database -Dtest=PostgreSQLDistTest,MariaDBDistTest#testSuccessful,MySQLDistTest#testSuccessful,DatabaseOptionsDistTest,JPAStoreDistTest,HotRodStoreDistTest,MixedStoreDistTest,TransactionConfigurationDistTest"
|
||||
|
||||
./mvnw install -nsu -B -pl quarkus/tests/integration -am -DskipTests
|
||||
./mvnw test -nsu -B -pl quarkus/tests/integration ${PARAMS["${{ matrix.server }}"]} | misc/log/trimmer.sh
|
||||
|
|
|
@ -8,11 +8,4 @@ public class TransactionOptions {
|
|||
.buildTime(true)
|
||||
.defaultValue(Boolean.TRUE)
|
||||
.build();
|
||||
|
||||
public static final Option<Boolean> TRANSACTION_JTA_ENABLED = new OptionBuilder<>("transaction-jta-enabled", Boolean.class)
|
||||
.category(OptionCategory.TRANSACTION)
|
||||
.description("Set if distributed transactions are supported. If set to false, transactions are managed by the server and can not be joined if multiple data sources are used. By default, distributed transactions are enabled and only XA data sources can be used.")
|
||||
.buildTime(true)
|
||||
.hidden()
|
||||
.build();
|
||||
}
|
||||
|
|
|
@ -114,14 +114,7 @@ final class DatabasePropertyMappers {
|
|||
}
|
||||
|
||||
ConfigValue xaEnabledConfigValue = context.proceed("kc.transaction-xa-enabled");
|
||||
ConfigValue jtaEnabledConfiguration = context.proceed("kc.transaction-jta-enabled");
|
||||
|
||||
boolean isXaEnabled = xaEnabledConfigValue == null || Boolean.parseBoolean(xaEnabledConfigValue.getValue());
|
||||
boolean isJtaEnabled = jtaEnabledConfiguration == null || Boolean.parseBoolean(jtaEnabledConfiguration.getValue());
|
||||
|
||||
if (!isJtaEnabled) {
|
||||
isXaEnabled = false;
|
||||
}
|
||||
|
||||
Optional<String> driver = Database.getDriver(value.get(), isXaEnabled);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import io.smallrye.config.ConfigValue;
|
|||
|
||||
import org.keycloak.config.StorageOptions;
|
||||
import org.keycloak.config.TransactionOptions;
|
||||
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||
|
||||
import static java.util.Optional.of;
|
||||
import static org.keycloak.config.StorageOptions.STORAGE;
|
||||
|
@ -23,11 +24,6 @@ public class TransactionPropertyMappers {
|
|||
return new PropertyMapper[] {
|
||||
fromOption(TransactionOptions.TRANSACTION_XA_ENABLED)
|
||||
.to(QUARKUS_TXPROP_TARGET)
|
||||
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
|
||||
.transformer(TransactionPropertyMappers::getQuarkusTransactionsValue)
|
||||
.build(),
|
||||
fromOption(TransactionOptions.TRANSACTION_JTA_ENABLED)
|
||||
.paramLabel(Boolean.TRUE + "|" + Boolean.FALSE)
|
||||
.transformer(TransactionPropertyMappers::getQuarkusTransactionsValue)
|
||||
.build()
|
||||
};
|
||||
|
@ -35,32 +31,16 @@ public class TransactionPropertyMappers {
|
|||
|
||||
private static Optional<String> getQuarkusTransactionsValue(Optional<String> txValue, ConfigSourceInterceptorContext context) {
|
||||
boolean isXaEnabled = Boolean.parseBoolean(txValue.get());
|
||||
boolean isJtaEnabled = getBooleanValue("kc.transaction-jta-enabled", context, true);
|
||||
ConfigValue storage = context.proceed(NS_KEYCLOAK_PREFIX.concat(STORAGE.getKey()));
|
||||
|
||||
if (storage != null && StorageOptions.StorageType.jpa.name().equals(storage.getValue())) {
|
||||
isJtaEnabled = true;
|
||||
isXaEnabled = true;
|
||||
}
|
||||
|
||||
if (!isJtaEnabled) {
|
||||
return of("disabled");
|
||||
}
|
||||
|
||||
if (isXaEnabled) {
|
||||
return of("xa");
|
||||
}
|
||||
|
||||
return of("enabled");
|
||||
}
|
||||
|
||||
private static boolean getBooleanValue(String key, ConfigSourceInterceptorContext context, boolean defaultValue) {
|
||||
boolean returnValue = defaultValue;
|
||||
ConfigValue configValue = context.proceed(key);
|
||||
|
||||
if (configValue != null) {
|
||||
returnValue = Boolean.parseBoolean(configValue.getValue());
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ import io.quarkus.hibernate.orm.PersistenceUnit;
|
|||
public abstract class AbstractJpaConnectionProviderFactory implements JpaConnectionProviderFactory {
|
||||
|
||||
protected Config.Scope config;
|
||||
protected Boolean xaEnabled;
|
||||
protected EntityManagerFactory entityManagerFactory;
|
||||
|
||||
@Override
|
||||
|
@ -62,7 +61,6 @@ public abstract class AbstractJpaConnectionProviderFactory implements JpaConnect
|
|||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
this.config = config;
|
||||
xaEnabled = "xa".equals(Configuration.getRawValue("kc.transaction-xa-enabled"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -101,13 +99,7 @@ public abstract class AbstractJpaConnectionProviderFactory implements JpaConnect
|
|||
}
|
||||
|
||||
protected EntityManager createEntityManager(EntityManagerFactory emf, KeycloakSession session) {
|
||||
EntityManager entityManager;
|
||||
|
||||
if (xaEnabled) {
|
||||
entityManager = PersistenceExceptionConverter.create(session, emf.createEntityManager(SynchronizationType.SYNCHRONIZED));
|
||||
} else {
|
||||
entityManager = PersistenceExceptionConverter.create(session, emf.createEntityManager());
|
||||
}
|
||||
EntityManager entityManager = PersistenceExceptionConverter.create(session, emf.createEntityManager(SynchronizationType.SYNCHRONIZED));
|
||||
|
||||
entityManager.setFlushMode(FlushModeType.AUTO);
|
||||
|
||||
|
|
|
@ -443,12 +443,6 @@ public class ConfigurationTest {
|
|||
|
||||
assertEquals("com.microsoft.sqlserver.jdbc.SQLServerXADataSource", xaConfig.getConfigValue("quarkus.datasource.jdbc.driver").getValue());
|
||||
assertEquals("xa", xaConfig.getConfigValue("quarkus.datasource.jdbc.transactions").getValue());
|
||||
|
||||
System.setProperty(CLI_ARGS, "--db=mssql" + ARG_SEPARATOR + "--transaction-jta-enabled=false");
|
||||
SmallRyeConfig jtaDisabledConfig = createConfig();
|
||||
|
||||
assertEquals("com.microsoft.sqlserver.jdbc.SQLServerDriver", jtaDisabledConfig.getConfigValue("quarkus.datasource.jdbc.driver").getValue());
|
||||
assertEquals("disabled", jtaDisabledConfig.getConfigValue("quarkus.datasource.jdbc.transactions").getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.it.storage.database;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.it.junit5.extension.CLIResult;
|
||||
import org.keycloak.it.junit5.extension.CLITest;
|
||||
import org.keycloak.it.junit5.extension.WithDatabase;
|
||||
|
||||
import io.quarkus.test.junit.main.Launch;
|
||||
import io.quarkus.test.junit.main.LaunchResult;
|
||||
|
||||
@CLITest
|
||||
@WithDatabase(alias = "mssql")
|
||||
public class MSSQLTest extends BasicDatabaseTest {
|
||||
|
||||
/**
|
||||
* It should be possible to enable XA but here we reproduce a managed environment where only nonXA transaction is supported
|
||||
*
|
||||
* @param result
|
||||
*/
|
||||
@Override
|
||||
@Test
|
||||
@Launch({ "--transaction-xa-enabled=false", "start-dev" })
|
||||
void testSuccessful(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
cliResult.assertStartedDevMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertWrongUsername(CLIResult cliResult) {
|
||||
cliResult.assertMessage("ERROR: Login failed for user 'wrong'");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assertWrongPassword(CLIResult cliResult) {
|
||||
cliResult.assertMessage("Login failed for user");
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.it.storage.database.dist;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.it.junit5.extension.CLIResult;
|
||||
import org.keycloak.it.junit5.extension.DistributionTest;
|
||||
|
||||
import io.quarkus.test.junit.main.Launch;
|
||||
import io.quarkus.test.junit.main.LaunchResult;
|
||||
|
||||
@DistributionTest
|
||||
public class CustomTransactionDistTest {
|
||||
|
||||
@Test
|
||||
@Launch({ "build", "--db=mssql", "--transaction-xa-enabled=false" })
|
||||
void testNoXa(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
cliResult.assertBuild();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package org.keycloak.it.storage.database.dist;
|
||||
|
||||
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.LegacyStore;
|
||||
import org.keycloak.it.junit5.extension.WithDatabase;
|
||||
|
||||
@DistributionTest
|
||||
@WithDatabase(alias = "mssql")
|
||||
@LegacyStore
|
||||
public class TransactionConfigurationDistTest {
|
||||
|
||||
@Test
|
||||
@Launch({ "start-dev", "--db=mssql", "--transaction-xa-enabled=false" })
|
||||
void testXADisabled(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
cliResult.assertStartedDevMode();
|
||||
cliResult.assertNoMessage("ARJUNA016061: TransactionImple.enlistResource");
|
||||
}
|
||||
|
||||
}
|
|
@ -1 +1 @@
|
|||
mcr.microsoft.com/mssql/server:2019-CU10-ubuntu-20.04
|
||||
mcr.microsoft.com/mssql/server:2019-latest
|
|
@ -87,6 +87,10 @@
|
|||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>mysql</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>mssqlserver</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.wagon</groupId>
|
||||
<artifactId>wagon-http-shared</artifactId>
|
||||
|
|
|
@ -22,11 +22,11 @@ import java.time.Duration;
|
|||
import org.keycloak.it.utils.KeycloakDistribution;
|
||||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.JdbcDatabaseContainer;
|
||||
import org.testcontainers.containers.MSSQLServerContainer;
|
||||
import org.testcontainers.containers.MariaDBContainer;
|
||||
import org.testcontainers.containers.MySQLContainer;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
import org.testcontainers.utility.DockerImageName;
|
||||
|
||||
public class DatabaseContainer {
|
||||
|
||||
|
@ -59,7 +59,6 @@ public class DatabaseContainer {
|
|||
dist.setProperty("db-password", getPassword());
|
||||
dist.setProperty("db-url", getJdbcUrl());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String getJdbcUrl() {
|
||||
|
@ -67,10 +66,16 @@ public class DatabaseContainer {
|
|||
}
|
||||
|
||||
String getUsername() {
|
||||
if (container instanceof MSSQLServerContainer) {
|
||||
return ((JdbcDatabaseContainer) container).getUsername();
|
||||
}
|
||||
return "keycloak";
|
||||
}
|
||||
|
||||
String getPassword() {
|
||||
if (container instanceof MSSQLServerContainer) {
|
||||
return ((JdbcDatabaseContainer) container).getPassword();
|
||||
}
|
||||
return DEFAULT_PASSWORD;
|
||||
}
|
||||
|
||||
|
@ -79,7 +84,11 @@ public class DatabaseContainer {
|
|||
container = null;
|
||||
}
|
||||
|
||||
private GenericContainer<?> configureJdbcContainer(JdbcDatabaseContainer jdbcDatabaseContainer) {
|
||||
private JdbcDatabaseContainer configureJdbcContainer(JdbcDatabaseContainer jdbcDatabaseContainer) {
|
||||
if (jdbcDatabaseContainer instanceof MSSQLServerContainer) {
|
||||
return jdbcDatabaseContainer;
|
||||
}
|
||||
|
||||
return jdbcDatabaseContainer
|
||||
.withDatabaseName("keycloak")
|
||||
.withUsername(getUsername())
|
||||
|
@ -98,10 +107,12 @@ public class DatabaseContainer {
|
|||
String MARIADB_IMAGE = System.getProperty("kc.db.mariadb.container.image", "mariadb:10.5.9");
|
||||
String MYSQL_IMAGE = System.getProperty("kc.db.mysql.container.image", "mysql:latest");
|
||||
String INFINISPAN_IMAGE = System.getProperty("kc.infinispan.container.image");
|
||||
String MSSQL_IMAGE = System.getProperty("kc.db.mssql.container.image", "mcr.microsoft.com/mssql/server:2019-latest");
|
||||
|
||||
DockerImageName POSTGRES = DockerImageName.parse(POSTGRES_IMAGE).asCompatibleSubstituteFor("postgres");
|
||||
DockerImageName MARIADB = DockerImageName.parse(MARIADB_IMAGE).asCompatibleSubstituteFor("mariadb");
|
||||
DockerImageName MYSQL = DockerImageName.parse(MYSQL_IMAGE).asCompatibleSubstituteFor("mysql");
|
||||
DockerImageName MSSQL = DockerImageName.parse(MSSQL_IMAGE).asCompatibleSubstituteFor("sqlserver");
|
||||
|
||||
switch (alias) {
|
||||
case "postgres":
|
||||
|
@ -110,6 +121,8 @@ public class DatabaseContainer {
|
|||
return configureJdbcContainer(new MariaDBContainer(MARIADB));
|
||||
case "mysql":
|
||||
return configureJdbcContainer(new MySQLContainer(MYSQL));
|
||||
case "mssql":
|
||||
return configureJdbcContainer(new MSSQLServerContainer(MSSQL));
|
||||
case "infinispan":
|
||||
return configureInfinispanUser(new GenericContainer(INFINISPAN_IMAGE))
|
||||
.withExposedPorts(11222);
|
||||
|
|
Loading…
Reference in a new issue