Improvements to configuration
This commit is contained in:
parent
e131de9574
commit
452bcd8bd9
11 changed files with 174 additions and 116 deletions
|
@ -104,6 +104,10 @@
|
|||
<source>target/keycloak-quarkus-server/cluster-default.xml</source>
|
||||
<outputDirectory>conf</outputDirectory>
|
||||
</file>
|
||||
<file>
|
||||
<source>target/keycloak-quarkus-server-app/META-INF/keycloak.properties</source>
|
||||
<outputDirectory>conf</outputDirectory>
|
||||
</file>
|
||||
</files>
|
||||
|
||||
</assembly>
|
||||
|
|
|
@ -70,6 +70,12 @@
|
|||
<type>jar</type>
|
||||
<outputDirectory>target/keycloak-quarkus-server</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-quarkus-server-app</artifactId>
|
||||
<type>jar</type>
|
||||
<outputDirectory>target/keycloak-quarkus-server-app</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
# Configure the server
|
||||
|
||||
Use files in this directory to configure the server
|
|
@ -1,12 +0,0 @@
|
|||
# Default and non-production grade database vendor
|
||||
db=h2-file
|
||||
|
||||
# Default, and insecure, and non-production grade configuration for the development profile
|
||||
%dev.http.enabled=true
|
||||
%dev.db.username = sa
|
||||
%dev.db.password = keycloak
|
||||
|
||||
# Logging configuration. INFO is the default level for most of the categories
|
||||
#quarkus.log.level = DEBUG
|
||||
quarkus.log.category."org.jboss.resteasy.resteasy_jaxrs.i18n".level=WARN
|
||||
quarkus.log.category."org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup".level=WARN
|
|
@ -102,7 +102,7 @@ class KeycloakProcessor {
|
|||
*
|
||||
* @param recorder
|
||||
*/
|
||||
@Record(ExecutionTime.STATIC_INIT)
|
||||
@Record(ExecutionTime.RUNTIME_INIT)
|
||||
@BuildStep
|
||||
void configureProviders(KeycloakRecorder recorder) {
|
||||
Profile.setInstance(recorder.createProfile());
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright 2020 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.configuration;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
class Database {
|
||||
|
||||
private static Map<String, Vendor> DATABASES = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (Vendor vendor : Vendor.values()) {
|
||||
DATABASES.put(vendor.name().toLowerCase(), vendor);
|
||||
|
||||
for (String alias : vendor.aliases) {
|
||||
DATABASES.put(alias, vendor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isSupported(String alias) {
|
||||
return DATABASES.containsKey(alias);
|
||||
}
|
||||
|
||||
static Optional<String> getDefaultUrl(String alias) {
|
||||
Vendor vendor = DATABASES.get(alias);
|
||||
|
||||
if (vendor == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(vendor.defaultUrl.apply(alias));
|
||||
}
|
||||
|
||||
static Optional<String> getDriver(String alias) {
|
||||
Vendor vendor = DATABASES.get(alias);
|
||||
|
||||
if (vendor == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(vendor.driver);
|
||||
}
|
||||
|
||||
static Optional<String> getDialect(String alias) {
|
||||
Vendor vendor = DATABASES.get(alias);
|
||||
|
||||
if (vendor == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return Optional.of(vendor.dialect.apply(alias));
|
||||
}
|
||||
|
||||
private enum Vendor {
|
||||
H2("org.h2.jdbcx.JdbcDataSource", "io.quarkus.hibernate.orm.runtime.dialect.QuarkusH2Dialect",
|
||||
new Function<String, String>() {
|
||||
@Override
|
||||
public String apply(String alias) {
|
||||
if ("h2-file".equalsIgnoreCase(alias)) {
|
||||
return "jdbc:h2:file:${kc.home.dir:${kc.db.url.path:~}}/${kc.data.dir:data}/keycloakdb${kc.db.url.properties:;;AUTO_SERVER=TRUE}";
|
||||
}
|
||||
return "jdbc:h2:mem:keycloakdb${kc.db.url.properties:}";
|
||||
}
|
||||
}, "h2-mem", "h2-file"),
|
||||
MYSQL("com.mysql.cj.jdbc.MysqlXADataSource", "org.hibernate.dialect.MySQL8Dialect",
|
||||
"jdbc:mysql://${kc.db.url.host:localhost}/${kc.db.url.database:keycloak}${kc.db.url.properties:}"),
|
||||
MARIADB("org.mariadb.jdbc.MySQLDataSource", "org.hibernate.dialect.MariaDBDialect",
|
||||
"jdbc:mariadb://${kc.db.url.host:localhost}/${kc.db.url.database:keycloak}${kc.db.url.properties:}"),
|
||||
POSTGRES("org.postgresql.xa.PGXADataSource", new Function<String, String>() {
|
||||
@Override
|
||||
public String apply(String alias) {
|
||||
if ("postgres-95".equalsIgnoreCase(alias)) {
|
||||
return "io.quarkus.hibernate.orm.runtime.dialect.QuarkusPostgreSQL95Dialect";
|
||||
}
|
||||
return "io.quarkus.hibernate.orm.runtime.dialect.QuarkusPostgreSQL10Dialect";
|
||||
}
|
||||
}, "jdbc:postgresql://${kc.db.url.host:localhost}/${kc.db.url.database:keycloak}${kc.db.url.properties:}",
|
||||
"postgres-95", "postgres-10");
|
||||
|
||||
final String driver;
|
||||
final Function<String, String> dialect;
|
||||
final Function<String, String> defaultUrl;
|
||||
final String[] aliases;
|
||||
|
||||
Vendor(String driver, String dialect, String defaultUrl, String... aliases) {
|
||||
this(driver, (alias) -> dialect, (alias) -> defaultUrl, aliases);
|
||||
}
|
||||
|
||||
Vendor(String driver, String dialect, Function<String, String> defaultUrl, String... aliases) {
|
||||
this(driver, (alias) -> dialect, defaultUrl, aliases);
|
||||
}
|
||||
|
||||
Vendor(String driver, Function<String, String> dialect, String defaultUrl, String... aliases) {
|
||||
this(driver, dialect, (alias) -> defaultUrl, aliases);
|
||||
}
|
||||
|
||||
Vendor(String driver, Function<String, String> dialect, Function<String, String> defaultUrl, String... aliases) {
|
||||
this.driver = driver;
|
||||
this.dialect = dialect;
|
||||
this.defaultUrl = defaultUrl;
|
||||
this.aliases = aliases;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,15 +17,12 @@
|
|||
|
||||
package org.keycloak.configuration;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
|
@ -62,13 +59,9 @@ public abstract class KeycloakPropertiesConfigSource extends PropertiesConfigSou
|
|||
return Collections.emptyMap();
|
||||
}
|
||||
try (Closeable ignored = is) {
|
||||
try (InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8)) {
|
||||
try (BufferedReader br = new BufferedReader(isr)) {
|
||||
final Properties properties = new Properties();
|
||||
properties.load(br);
|
||||
return transform((Map<String, String>) (Map) properties);
|
||||
}
|
||||
}
|
||||
Properties properties = new Properties();
|
||||
properties.load(is);
|
||||
return transform((Map<String, String>) (Map) properties);
|
||||
} catch (IOException e) {
|
||||
throw new IOError(e);
|
||||
}
|
||||
|
|
|
@ -53,8 +53,7 @@ public final class PropertyMappers {
|
|||
Boolean enabled = Boolean.valueOf(value);
|
||||
ConfigValue proxy = context.proceed(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX + "proxy");
|
||||
|
||||
if ("dev".equalsIgnoreCase(ProfileManager.getActiveProfile()) ||
|
||||
(proxy != null && "edge".equalsIgnoreCase(proxy.getValue()))) {
|
||||
if (Environment.isDevMode() || (proxy != null && "edge".equalsIgnoreCase(proxy.getValue()))) {
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
|
@ -119,74 +118,17 @@ public final class PropertyMappers {
|
|||
}
|
||||
|
||||
private static void configureDatabasePropertyMappers() {
|
||||
createBuildTimeProperty("db", "quarkus.hibernate-orm.dialect", (db, context) -> {
|
||||
switch (db.toLowerCase()) {
|
||||
case "h2-file":
|
||||
case "h2-mem":
|
||||
return "io.quarkus.hibernate.orm.runtime.dialect.QuarkusH2Dialect";
|
||||
case "mariadb":
|
||||
return "org.hibernate.dialect.MariaDBDialect";
|
||||
case "mysql":
|
||||
return "org.hibernate.dialect.MySQL8Dialect";
|
||||
case "postgres-95":
|
||||
return "io.quarkus.hibernate.orm.runtime.dialect.QuarkusPostgreSQL95Dialect";
|
||||
case "postgres": // shorthand for the recommended postgres version
|
||||
case "postgres-10":
|
||||
return "io.quarkus.hibernate.orm.runtime.dialect.QuarkusPostgreSQL10Dialect";
|
||||
}
|
||||
return null;
|
||||
}, null);
|
||||
create("db", "quarkus.datasource.jdbc.driver", (db, context) -> {
|
||||
switch (db.toLowerCase()) {
|
||||
case "h2-file":
|
||||
case "h2-mem":
|
||||
return "org.h2.jdbcx.JdbcDataSource";
|
||||
case "mariadb":
|
||||
return "org.mariadb.jdbc.MySQLDataSource";
|
||||
case "mysql":
|
||||
return "com.mysql.cj.jdbc.MysqlXADataSource";
|
||||
case "postgres":
|
||||
case "postgres-95":
|
||||
case "postgres-10":
|
||||
return "org.postgresql.xa.PGXADataSource";
|
||||
}
|
||||
return null;
|
||||
}, null);
|
||||
create("db", "quarkus.datasource.db-kind", (db, context) -> {
|
||||
switch (db.toLowerCase()) {
|
||||
case "h2-file":
|
||||
case "h2-mem":
|
||||
return "h2";
|
||||
case "mariadb":
|
||||
return "mariadb";
|
||||
case "mysql":
|
||||
return "mysql";
|
||||
case "postgres":
|
||||
case "postgres-95":
|
||||
case "postgres-10":
|
||||
return "postgresql";
|
||||
createBuildTimeProperty("db", "quarkus.hibernate-orm.dialect", (db, context) -> Database.getDialect(db).orElse(null), null);
|
||||
create("db", "quarkus.datasource.jdbc.driver", (db, context) -> Database.getDriver(db).orElse(null), null);
|
||||
createBuildTimeProperty("db", "quarkus.datasource.db-kind", (db, context) -> {
|
||||
if (Database.isSupported(db)) {
|
||||
return db;
|
||||
}
|
||||
addInitializationException(invalidDatabaseVendor(db, "h2-file", "h2-mem", "mariadb", "mysql", "postgres", "postgres-95", "postgres-10"));
|
||||
return "h2";
|
||||
}, "The database vendor. Possible values are: h2-mem, h2-file, mariadb, mysql, postgres95, postgres10.");
|
||||
create("db", "quarkus.datasource.jdbc.transactions", (db, context) -> "xa", null);
|
||||
create("db.url", "db", "quarkus.datasource.jdbc.url", (value, context) -> {
|
||||
switch (value.toLowerCase()) {
|
||||
case "h2-file":
|
||||
return "jdbc:h2:file:${kc.home.dir:${kc.db.url.path:~}}/${kc.data.dir:data}/keycloakdb${kc.db.url.properties:;;AUTO_SERVER=TRUE}";
|
||||
case "h2-mem":
|
||||
return "jdbc:h2:mem:keycloakdb${kc.db.url.properties:}";
|
||||
case "mariadb":
|
||||
return "jdbc:mariadb://${kc.db.url.host:localhost}/${kc.db.url.database:keycloak}${kc.db.url.properties:}";
|
||||
case "postgres":
|
||||
case "postgres-95":
|
||||
case "postgres-10":
|
||||
return "jdbc:postgresql://${kc.db.url.host:localhost}/${kc.db.url.database:keycloak}${kc.db.url.properties:}";
|
||||
case "mysql":
|
||||
return "jdbc:mysql://${kc.db.url.host:localhost}/${kc.db.url.database:keycloak}${kc.db.url.properties:}";
|
||||
}
|
||||
return value;
|
||||
}, "The database JDBC URL. If not provided a default URL is set based on the selected database vendor. For instance, if using 'postgres', the JDBC URL would be 'jdbc:postgresql://localhost/keycloak'. The host, database and properties can be overridden by setting the following system properties, respectively: -Dkc.db.url.host, -Dkc.db.url.database, -Dkc.db.url.properties.");
|
||||
create("db.url", "db", "quarkus.datasource.jdbc.url", (value, context) -> Database.getDefaultUrl(value).orElse(value), "The database JDBC URL. If not provided a default URL is set based on the selected database vendor. For instance, if using 'postgres', the JDBC URL would be 'jdbc:postgresql://localhost/keycloak'. The host, database and properties can be overridden by setting the following system properties, respectively: -Dkc.db.url.host, -Dkc.db.url.database, -Dkc.db.url.properties.");
|
||||
create("db.username", "quarkus.datasource.username", "The database username.");
|
||||
create("db.password", "quarkus.datasource.password", "The database password", true);
|
||||
create("db.schema", "quarkus.datasource.schema", "The database schema.");
|
||||
|
@ -212,11 +154,6 @@ public final class PropertyMappers {
|
|||
.anyMatch(entry -> entry.getValue().getFrom().equals(name) && entry.getValue().isBuildTime());
|
||||
}
|
||||
|
||||
public static boolean isSupported(String name) {
|
||||
return PropertyMapper.MAPPERS.entrySet().stream()
|
||||
.anyMatch(entry -> toCLIFormat(entry.getValue().getFrom()).equals(name));
|
||||
}
|
||||
|
||||
public static String toCLIFormat(String name) {
|
||||
if (name.indexOf('.') == -1) {
|
||||
return name;
|
||||
|
|
|
@ -17,14 +17,9 @@
|
|||
|
||||
package org.keycloak.provider.quarkus;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.infinispan.commons.util.FileLookupFactory;
|
||||
import org.infinispan.configuration.parsing.ConfigurationBuilderHolder;
|
||||
|
@ -45,8 +40,7 @@ public final class QuarkusCacheManagerProvider implements ManagedCacheManagerPro
|
|||
@Override
|
||||
public <C> C getCacheManager(Config.Scope config) {
|
||||
try {
|
||||
String configurationAsString = loadConfigurationToString(config);
|
||||
ConfigurationBuilderHolder builder = new ParserRegistry().parse(configurationAsString);
|
||||
ConfigurationBuilderHolder builder = new ParserRegistry().parse(loadConfiguration(config));
|
||||
|
||||
if (builder.getNamedConfigurationBuilders().get("sessions").clustering().cacheMode().isClustered()) {
|
||||
configureTransportStack(config, builder);
|
||||
|
@ -58,17 +52,12 @@ public final class QuarkusCacheManagerProvider implements ManagedCacheManagerPro
|
|||
}
|
||||
}
|
||||
|
||||
private String loadConfigurationToString(Config.Scope config) throws FileNotFoundException {
|
||||
BufferedReader configurationReader = new BufferedReader(new InputStreamReader(loadConfiguration(config), StandardCharsets.UTF_8));
|
||||
return configurationReader.lines().collect(Collectors.joining(System.lineSeparator()));
|
||||
}
|
||||
|
||||
private InputStream loadConfiguration(Config.Scope config) throws FileNotFoundException {
|
||||
private URL loadConfiguration(Config.Scope config) {
|
||||
String pathPrefix;
|
||||
String homeDir = Environment.getHomeDir();
|
||||
|
||||
if (homeDir == null) {
|
||||
log.warn("Keycloak home directory not set.");
|
||||
log.warn("Keycloak home directory not set");
|
||||
pathPrefix = "";
|
||||
} else {
|
||||
pathPrefix = homeDir + "/conf/";
|
||||
|
@ -78,18 +67,24 @@ public final class QuarkusCacheManagerProvider implements ManagedCacheManagerPro
|
|||
String configFile = config.get("configFile");
|
||||
if (configFile != null) {
|
||||
Path configPath = Paths.get(pathPrefix + configFile);
|
||||
String path;
|
||||
|
||||
if (configPath.toFile().exists()) {
|
||||
log.infof("Loading cache configuration from %s", configPath);
|
||||
return FileLookupFactory.newInstance()
|
||||
.lookupFileStrict(configPath.toUri(), Thread.currentThread().getContextClassLoader());
|
||||
path = configPath.toFile().getAbsolutePath();
|
||||
} else {
|
||||
log.infof("Loading cache configuration from %s", configPath);
|
||||
return FileLookupFactory.newInstance()
|
||||
.lookupFileStrict(configPath.getFileName().toString(), Thread.currentThread().getContextClassLoader());
|
||||
path = configPath.getFileName().toString();
|
||||
}
|
||||
|
||||
log.infof("Loading cluster configuration from %s", configPath);
|
||||
URL url = FileLookupFactory.newInstance().lookupFileLocation(path, Thread.currentThread().getContextClassLoader());
|
||||
|
||||
if (url == null) {
|
||||
throw new IllegalArgumentException("Could not load cluster configuration file at [" + configPath + "]");
|
||||
}
|
||||
|
||||
return url;
|
||||
} else {
|
||||
throw new IllegalStateException("Option 'configFile' needs to be specified");
|
||||
throw new IllegalArgumentException("Option 'configFile' needs to be specified");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,4 +79,8 @@ public final class Environment {
|
|||
public static SmallRyeConfig getConfig() {
|
||||
return KeycloakRecorder.getConfig();
|
||||
}
|
||||
|
||||
public static boolean isDevMode() {
|
||||
return "dev".equalsIgnoreCase(getProfile());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,4 +5,9 @@ db=h2-file
|
|||
%dev.http.enabled=true
|
||||
%dev.db.username = sa
|
||||
%dev.db.password = keycloak
|
||||
%dev.cluster=local
|
||||
%dev.cluster=local
|
||||
|
||||
# Logging configuration. INFO is the default level for most of the categories
|
||||
#quarkus.log.level = DEBUG
|
||||
quarkus.log.category."org.jboss.resteasy.resteasy_jaxrs.i18n".level=WARN
|
||||
quarkus.log.category."org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup".level=WARN
|
Loading…
Reference in a new issue