fix: consolidating logic dealing with persisted property handling (#34260)
closes: #34258 Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
parent
bd1a5a1543
commit
927f110aef
21 changed files with 387 additions and 533 deletions
|
@ -45,12 +45,11 @@ import io.quarkus.hibernate.orm.deployment.PersistenceXmlDescriptorBuildItem;
|
|||
import io.quarkus.hibernate.orm.deployment.integration.HibernateOrmIntegrationRuntimeConfiguredBuildItem;
|
||||
import io.quarkus.hibernate.orm.deployment.spi.AdditionalJpaModelBuildItem;
|
||||
import io.quarkus.resteasy.reactive.server.spi.MethodScannerBuildItem;
|
||||
import io.quarkus.runtime.LaunchMode;
|
||||
import io.quarkus.runtime.configuration.ConfigurationException;
|
||||
import io.quarkus.vertx.http.deployment.HttpRootPathBuildItem;
|
||||
import io.quarkus.vertx.http.deployment.NonApplicationRootPathBuildItem;
|
||||
import io.quarkus.vertx.http.deployment.RouteBuildItem;
|
||||
import io.smallrye.config.ConfigValue;
|
||||
|
||||
import org.eclipse.microprofile.health.Readiness;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor;
|
||||
|
@ -97,11 +96,11 @@ import org.keycloak.provider.ProviderManager;
|
|||
import org.keycloak.provider.Spi;
|
||||
import org.keycloak.quarkus.runtime.Environment;
|
||||
import org.keycloak.quarkus.runtime.KeycloakRecorder;
|
||||
import org.keycloak.quarkus.runtime.cli.Picocli;
|
||||
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||
import org.keycloak.quarkus.runtime.configuration.KeycloakConfigSourceProvider;
|
||||
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
|
||||
import org.keycloak.quarkus.runtime.configuration.PersistedConfigSource;
|
||||
import org.keycloak.quarkus.runtime.configuration.QuarkusPropertiesConfigSource;
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper;
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
|
||||
import org.keycloak.quarkus.runtime.integration.resteasy.KeycloakHandlerChainCustomizer;
|
||||
|
@ -130,7 +129,6 @@ import org.keycloak.vault.FilesPlainTextVaultProviderFactory;
|
|||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.spi.PersistenceUnitTransactionType;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
@ -153,14 +151,10 @@ import java.util.logging.Handler;
|
|||
|
||||
import static org.keycloak.connections.jpa.util.JpaUtils.loadSpecificNamedQueries;
|
||||
import static org.keycloak.quarkus.runtime.Environment.getCurrentOrCreateFeatureProfile;
|
||||
import static org.keycloak.quarkus.runtime.Environment.getProviderFiles;
|
||||
import static org.keycloak.quarkus.runtime.Providers.getProviderManager;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getOptionalKcValue;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getOptionalValue;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getPropertyNames;
|
||||
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX;
|
||||
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_QUARKUS;
|
||||
import static org.keycloak.quarkus.runtime.configuration.QuarkusPropertiesConfigSource.QUARKUS_PROPERTY_ENABLED;
|
||||
import static org.keycloak.quarkus.runtime.storage.database.jpa.QuarkusJpaConnectionProviderFactory.QUERY_PROPERTY_PREFIX;
|
||||
import static org.keycloak.representations.provider.ScriptProviderDescriptor.AUTHENTICATORS;
|
||||
import static org.keycloak.representations.provider.ScriptProviderDescriptor.MAPPERS;
|
||||
|
@ -578,31 +572,7 @@ class KeycloakProcessor {
|
|||
*/
|
||||
@BuildStep(onlyIf = IsReAugmentation.class)
|
||||
void persistBuildTimeProperties(BuildProducer<GeneratedResourceBuildItem> resources) {
|
||||
Properties properties = new Properties();
|
||||
|
||||
putPersistedProperty(properties, "kc.db");
|
||||
|
||||
for (String name : getPropertyNames()) {
|
||||
putPersistedProperty(properties, name);
|
||||
}
|
||||
|
||||
for (File jar : getProviderFiles().values()) {
|
||||
properties.put(String.format("kc.provider.file.%s.last-modified", jar.getName()), String.valueOf(jar.lastModified()));
|
||||
}
|
||||
|
||||
if (!Environment.isRebuildCheck()) {
|
||||
// not auto-build (e.g.: start without optimized option) but a regular build to create an optimized server image
|
||||
Configuration.markAsOptimized(properties);
|
||||
}
|
||||
|
||||
String profile = org.keycloak.common.util.Environment.getProfile();
|
||||
|
||||
if (profile != null) {
|
||||
properties.put(org.keycloak.common.util.Environment.PROFILE, profile);
|
||||
properties.put(LaunchMode.current().getProfileKey(), profile);
|
||||
}
|
||||
|
||||
properties.put(QUARKUS_PROPERTY_ENABLED, String.valueOf(QuarkusPropertiesConfigSource.getConfigurationFile() != null));
|
||||
Properties properties = Picocli.getNonPersistedBuildTimeOptions();
|
||||
|
||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
properties.store(outputStream, " Auto-generated, DO NOT change this file");
|
||||
|
@ -612,40 +582,6 @@ class KeycloakProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
private void putPersistedProperty(Properties properties, String name) {
|
||||
PropertyMapper<?> mapper = PropertyMappers.getMapper(name);
|
||||
ConfigValue value = null;
|
||||
|
||||
if (mapper == null) {
|
||||
if (name.startsWith(NS_QUARKUS)) {
|
||||
value = Configuration.getConfigValue(name);
|
||||
|
||||
if (!QuarkusPropertiesConfigSource.isSameSource(value)) {
|
||||
return;
|
||||
}
|
||||
} else if (PropertyMappers.isSpiBuildTimeProperty(name)) {
|
||||
value = Configuration.getConfigValue(name);
|
||||
}
|
||||
} else if (mapper.isBuildTime()) {
|
||||
name = mapper.getFrom();
|
||||
value = Configuration.getConfigValue(name);
|
||||
}
|
||||
|
||||
if (value != null && value.getValue() != null) {
|
||||
if (value.getConfigSourceName() == null) {
|
||||
// only persist build options resolved from config sources and not default values
|
||||
return;
|
||||
}
|
||||
String rawValue = value.getRawValue();
|
||||
|
||||
if (rawValue == null) {
|
||||
rawValue = value.getValue();
|
||||
}
|
||||
|
||||
properties.put(name, rawValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will cause quarkus to include specified modules in the jandex index. For example keycloak-services is needed as it includes
|
||||
* most of the JAX-RS resources, which are required to register Resteasy builtin providers.
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
|
||||
package org.keycloak.quarkus.runtime;
|
||||
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getBuildTimeProperty;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.nio.file.Path;
|
||||
|
@ -36,6 +34,7 @@ import io.smallrye.config.SmallRyeConfig;
|
|||
import org.apache.commons.lang3.SystemUtils;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.quarkus.runtime.cli.command.AbstractCommand;
|
||||
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||
import org.keycloak.quarkus.runtime.configuration.PersistedConfigSource;
|
||||
|
||||
public final class Environment {
|
||||
|
@ -109,21 +108,18 @@ public final class Environment {
|
|||
}
|
||||
}
|
||||
|
||||
public static String getCurrentOrPersistedProfile() {
|
||||
/**
|
||||
* Update the profile settings based upon what was set in the system, environment, or optionally persistent values
|
||||
*/
|
||||
public static String updateProfile(boolean usePersistent) {
|
||||
String profile = org.keycloak.common.util.Environment.getProfile();
|
||||
if(profile == null) {
|
||||
if(profile == null && usePersistent) {
|
||||
profile = PersistedConfigSource.getInstance().getValue(org.keycloak.common.util.Environment.PROFILE);
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
|
||||
public static String getProfileOrDefault(String defaultProfile) {
|
||||
String profile = org.keycloak.common.util.Environment.getProfile();
|
||||
|
||||
if (profile == null) {
|
||||
profile = defaultProfile;
|
||||
profile = Environment.PROD_PROFILE_VALUE;
|
||||
}
|
||||
|
||||
setProfile(profile);
|
||||
return profile;
|
||||
}
|
||||
|
||||
|
@ -132,7 +128,7 @@ public final class Environment {
|
|||
return true;
|
||||
}
|
||||
|
||||
return org.keycloak.common.util.Environment.DEV_PROFILE_VALUE.equals(getBuildTimeProperty(org.keycloak.common.util.Environment.PROFILE).orElse(null));
|
||||
return org.keycloak.common.util.Environment.DEV_PROFILE_VALUE.equals(Configuration.getNonPersistedConfigValue(org.keycloak.common.util.Environment.PROFILE).getValue());
|
||||
}
|
||||
|
||||
public static boolean isDevProfile(){
|
||||
|
@ -221,6 +217,10 @@ public final class Environment {
|
|||
return Boolean.getBoolean("kc.config.build-and-exit");
|
||||
}
|
||||
|
||||
public static void setRebuildCheck() {
|
||||
System.setProperty("kc.config.build-and-exit", "true");
|
||||
}
|
||||
|
||||
public static boolean isRebuilt() {
|
||||
return Boolean.getBoolean("kc.config.built");
|
||||
}
|
||||
|
|
|
@ -19,12 +19,9 @@ package org.keycloak.quarkus.runtime;
|
|||
|
||||
import static org.keycloak.quarkus.runtime.Environment.getKeycloakModeFromProfile;
|
||||
import static org.keycloak.quarkus.runtime.Environment.isDevProfile;
|
||||
import static org.keycloak.quarkus.runtime.Environment.getProfileOrDefault;
|
||||
import static org.keycloak.quarkus.runtime.Environment.isNonServerMode;
|
||||
import static org.keycloak.quarkus.runtime.Environment.isTestLaunchMode;
|
||||
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.OPTIMIZED_BUILD_OPTION_LONG;
|
||||
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.wasBuildEverRun;
|
||||
import static org.keycloak.quarkus.runtime.cli.command.Start.isDevProfileNotAllowed;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
|
@ -83,12 +80,8 @@ public class KeycloakMain implements QuarkusApplication {
|
|||
cliArgs.add("-h");
|
||||
} else if (isFastStart(cliArgs)) { // fast path for starting the server without bootstrapping CLI
|
||||
|
||||
if (!wasBuildEverRun()) {
|
||||
handleUsageError(Messages.optimizedUsedForFirstStartup());
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDevProfileNotAllowed()) {
|
||||
Environment.updateProfile(true);
|
||||
if (Environment.isDevProfile()) {
|
||||
handleUsageError(Messages.devProfileNotAllowedError(Start.NAME));
|
||||
return;
|
||||
}
|
||||
|
@ -156,7 +149,7 @@ public class KeycloakMain implements QuarkusApplication {
|
|||
Quarkus.run(KeycloakMain.class, (exitCode, cause) -> {
|
||||
if (cause != null) {
|
||||
errorHandler.error(errStream,
|
||||
String.format("Failed to start server in (%s) mode", getKeycloakModeFromProfile(getProfileOrDefault("prod"))),
|
||||
String.format("Failed to start server in (%s) mode", getKeycloakModeFromProfile(org.keycloak.common.util.Environment.getProfile())),
|
||||
cause.getCause());
|
||||
}
|
||||
|
||||
|
@ -168,7 +161,7 @@ public class KeycloakMain implements QuarkusApplication {
|
|||
}, args);
|
||||
} catch (Throwable cause) {
|
||||
errorHandler.error(errStream,
|
||||
String.format("Unexpected error when starting the server in (%s) mode", getKeycloakModeFromProfile(getProfileOrDefault("prod"))),
|
||||
String.format("Unexpected error when starting the server in (%s) mode", getKeycloakModeFromProfile(org.keycloak.common.util.Environment.getProfile())),
|
||||
cause.getCause());
|
||||
System.exit(1);
|
||||
}
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
package org.keycloak.quarkus.runtime.cli;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static java.util.stream.StreamSupport.stream;
|
||||
import static org.keycloak.quarkus.runtime.Environment.getProviderFiles;
|
||||
import static org.keycloak.quarkus.runtime.Environment.isDevMode;
|
||||
import static org.keycloak.quarkus.runtime.Environment.isRebuild;
|
||||
import static org.keycloak.quarkus.runtime.Environment.isRebuildCheck;
|
||||
import static org.keycloak.quarkus.runtime.Environment.isRebuilt;
|
||||
|
@ -27,16 +27,9 @@ import static org.keycloak.quarkus.runtime.cli.OptionRenderer.decorateDuplicitOp
|
|||
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.OPTIMIZED_BUILD_OPTION_LONG;
|
||||
import static org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource.parseConfigArgs;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.OPTION_PART_SEPARATOR;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getBuildTimeProperty;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getConfig;
|
||||
import static org.keycloak.quarkus.runtime.Environment.isDevMode;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getCurrentBuiltTimeProperty;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getRawPersistedProperty;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getRuntimeProperty;
|
||||
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX;
|
||||
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.maskValue;
|
||||
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.isBuildTimeProperty;
|
||||
import static org.keycloak.utils.StringUtil.isNotBlank;
|
||||
import static picocli.CommandLine.Model.UsageMessageSpec.SECTION_KEY_COMMAND_LIST;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -44,62 +37,59 @@ import java.io.PrintWriter;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.microprofile.config.spi.ConfigSource;
|
||||
import org.keycloak.common.profile.ProfileException;
|
||||
import org.keycloak.config.DeprecatedMetadata;
|
||||
import org.keycloak.config.Option;
|
||||
import org.keycloak.config.OptionCategory;
|
||||
import org.keycloak.quarkus.runtime.Environment;
|
||||
import org.keycloak.quarkus.runtime.KeycloakMain;
|
||||
import org.keycloak.quarkus.runtime.Messages;
|
||||
import org.keycloak.quarkus.runtime.cli.command.AbstractCommand;
|
||||
import org.keycloak.quarkus.runtime.cli.command.BootstrapAdmin;
|
||||
import org.keycloak.quarkus.runtime.cli.command.Build;
|
||||
import org.keycloak.quarkus.runtime.cli.command.Completion;
|
||||
import org.keycloak.quarkus.runtime.cli.command.Main;
|
||||
import org.keycloak.quarkus.runtime.cli.command.ShowConfig;
|
||||
import org.keycloak.quarkus.runtime.cli.command.Start;
|
||||
import org.keycloak.quarkus.runtime.cli.command.StartDev;
|
||||
import org.keycloak.quarkus.runtime.cli.command.Tools;
|
||||
import org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource;
|
||||
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||
import org.keycloak.quarkus.runtime.configuration.DisabledMappersInterceptor;
|
||||
import org.keycloak.quarkus.runtime.configuration.KcUnmatchedArgumentException;
|
||||
import org.keycloak.quarkus.runtime.configuration.PersistedConfigSource;
|
||||
import org.keycloak.quarkus.runtime.configuration.KeycloakPropertiesConfigSource;
|
||||
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
|
||||
import org.keycloak.quarkus.runtime.configuration.PropertyMappingInterceptor;
|
||||
import org.keycloak.quarkus.runtime.configuration.QuarkusPropertiesConfigSource;
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper;
|
||||
import org.keycloak.quarkus.runtime.Environment;
|
||||
import org.keycloak.quarkus.runtime.KeycloakMain;
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
|
||||
|
||||
import io.quarkus.bootstrap.runner.QuarkusEntryPoint;
|
||||
import io.quarkus.runtime.LaunchMode;
|
||||
import io.smallrye.config.ConfigValue;
|
||||
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.ParameterException;
|
||||
import picocli.CommandLine.ParseResult;
|
||||
import picocli.CommandLine.DuplicateOptionAnnotationsException;
|
||||
import picocli.CommandLine.Help.Ansi;
|
||||
import picocli.CommandLine.Help.Ansi.Style;
|
||||
import picocli.CommandLine.Help.ColorScheme;
|
||||
import picocli.CommandLine.IFactory;
|
||||
import picocli.CommandLine.Model.ArgGroupSpec;
|
||||
import picocli.CommandLine.Model.CommandSpec;
|
||||
import picocli.CommandLine.Model.ISetter;
|
||||
import picocli.CommandLine.Model.OptionSpec;
|
||||
import picocli.CommandLine.Model.ArgGroupSpec;
|
||||
import picocli.CommandLine.ParameterException;
|
||||
import picocli.CommandLine.ParseResult;
|
||||
|
||||
public class Picocli {
|
||||
|
||||
private static final String KC_PROVIDER_FILE_PREFIX = "kc.provider.file.";
|
||||
public static final String ARG_PREFIX = "--";
|
||||
public static final String ARG_SHORT_PREFIX = "-";
|
||||
public static final String NO_PARAM_LABEL = "none";
|
||||
|
@ -172,7 +162,13 @@ public class Picocli {
|
|||
}
|
||||
|
||||
if (currentSpec != null) {
|
||||
addCommandOptions(cliArgs, currentSpec.commandLine());
|
||||
CommandLine commandLine = currentSpec.commandLine();
|
||||
addCommandOptions(cliArgs, commandLine);
|
||||
|
||||
if (commandLine != null && commandLine.getCommand() instanceof AbstractCommand ac) {
|
||||
// set current parsed command
|
||||
Environment.setParsedCommand(ac);
|
||||
}
|
||||
}
|
||||
|
||||
if (isRebuildCheck()) {
|
||||
|
@ -207,7 +203,7 @@ public class Picocli {
|
|||
}
|
||||
}
|
||||
|
||||
protected int runReAugmentationIfNeeded(List<String> cliArgs, CommandLine cmd, CommandLine currentCommand) {
|
||||
private int runReAugmentationIfNeeded(List<String> cliArgs, CommandLine cmd, CommandLine currentCommand) {
|
||||
int exitCode = 0;
|
||||
|
||||
if (currentCommand == null) {
|
||||
|
@ -220,14 +216,10 @@ public class Picocli {
|
|||
return exitCode;
|
||||
}
|
||||
|
||||
if (currentCommandName.equals(StartDev.NAME)) {
|
||||
String profile = org.keycloak.common.util.Environment.getProfile();
|
||||
// TODO: ensure that the config has not yet been initialized
|
||||
// - there's currently no good way to do that directly on ConfigProviderResolver
|
||||
initProfile(cliArgs, currentCommandName);
|
||||
|
||||
if (profile == null) {
|
||||
// force the server image to be set with the dev profile
|
||||
Environment.forceDevProfile();
|
||||
}
|
||||
}
|
||||
if (requiresReAugmentation(currentCommand)) {
|
||||
PropertyMappers.sanitizeDisabledMappers();
|
||||
exitCode = runReAugmentation(cliArgs, cmd);
|
||||
|
@ -236,34 +228,42 @@ public class Picocli {
|
|||
return exitCode;
|
||||
}
|
||||
|
||||
protected void initProfile(List<String> cliArgs, String currentCommandName) {
|
||||
if (currentCommandName.equals(StartDev.NAME)) {
|
||||
// force the server image to be set with the dev profile
|
||||
Environment.forceDevProfile();
|
||||
} else {
|
||||
Environment.updateProfile(false);
|
||||
|
||||
// override from the cli if specified
|
||||
parseConfigArgs(cliArgs, (k, v) -> {
|
||||
if (k.equals(Main.PROFILE_SHORT_NAME) || k.equals(Main.PROFILE_LONG_NAME)) {
|
||||
Environment.setProfile(v);
|
||||
}
|
||||
}, ignored -> {});
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean shouldSkipRebuild(List<String> cliArgs, String currentCommandName) {
|
||||
return cliArgs.contains("--help")
|
||||
|| cliArgs.contains("-h")
|
||||
|| cliArgs.contains("--help-all")
|
||||
|| currentCommandName.equals(Build.NAME)
|
||||
|| currentCommandName.equals(ShowConfig.NAME)
|
||||
|| currentCommandName.equals(BootstrapAdmin.NAME)
|
||||
|| currentCommandName.equals(Tools.NAME);
|
||||
|| currentCommandName.equals(Completion.NAME);
|
||||
}
|
||||
|
||||
private static boolean requiresReAugmentation(CommandLine cmdCommand) {
|
||||
if (ConfigArgsConfigSource.getAllCliArgs().contains(Start.NAME)
|
||||
// run time dev mode is not set
|
||||
&& !org.keycloak.common.util.Environment.isDevMode()
|
||||
// build time dev mode was set
|
||||
&& org.keycloak.common.util.Environment.DEV_PROFILE_VALUE.equals(getBuildTimeProperty(org.keycloak.common.util.Environment.PROFILE).orElse(null))) {
|
||||
return true;
|
||||
Map<String, String> rawPersistedProperties = Configuration.getRawPersistedProperties();
|
||||
if (rawPersistedProperties.isEmpty()) {
|
||||
return true; // no build yet
|
||||
}
|
||||
var current = getNonPersistedBuildTimeOptions();
|
||||
|
||||
if (hasConfigChanges(cmdCommand)) {
|
||||
if (!ConfigArgsConfigSource.getAllCliArgs().contains(StartDev.NAME) && "dev".equals(getConfig().getOptionalValue("kc.profile", String.class).orElse(null))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return hasProviderChanges();
|
||||
// everything but the optimized value must match
|
||||
String key = Configuration.KC_OPTIMIZED;
|
||||
Optional.ofNullable(rawPersistedProperties.get(key)).ifPresentOrElse(value -> current.put(key, value), () -> current.remove(key));
|
||||
return !rawPersistedProperties.equals(current);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -294,7 +294,9 @@ public class Picocli {
|
|||
private static int runReAugmentation(List<String> cliArgs, CommandLine cmd) {
|
||||
if(!isDevMode() && cmd != null) {
|
||||
cmd.getOut().println("Changes detected in configuration. Updating the server image.");
|
||||
checkChangesInBuildOptionsDuringAutoBuild();
|
||||
if (Configuration.isOptimized()) {
|
||||
checkChangesInBuildOptionsDuringAutoBuild(cmd.getOut());
|
||||
}
|
||||
}
|
||||
|
||||
List<String> configArgsList = new ArrayList<>();
|
||||
|
@ -316,36 +318,8 @@ public class Picocli {
|
|||
return exitCode;
|
||||
}
|
||||
|
||||
private static boolean hasProviderChanges() {
|
||||
Map<String, String> persistedProps = PersistedConfigSource.getInstance().getProperties();
|
||||
Map<String, File> deployedProviders = Environment.getProviderFiles();
|
||||
|
||||
if (persistedProps.isEmpty()) {
|
||||
return !deployedProviders.isEmpty();
|
||||
}
|
||||
|
||||
Set<String> providerKeys = persistedProps.keySet().stream().filter(Picocli::isProviderKey).collect(Collectors.toSet());
|
||||
|
||||
if (deployedProviders.size() != providerKeys.size()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (String key : providerKeys) {
|
||||
String fileName = key.substring("kc.provider.file".length() + 1, key.lastIndexOf('.'));
|
||||
|
||||
if (!deployedProviders.containsKey(fileName)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
File file = deployedProviders.get(fileName);
|
||||
String lastModified = persistedProps.get(key);
|
||||
|
||||
if (!lastModified.equals(String.valueOf(file.lastModified()))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
private static boolean wasBuildEverRun() {
|
||||
return !Configuration.getRawPersistedProperties().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -356,6 +330,10 @@ public class Picocli {
|
|||
* @param outWriter
|
||||
*/
|
||||
public static void validateConfig(List<String> cliArgs, AbstractCommand abstractCommand, PrintWriter outWriter) {
|
||||
if (cliArgs.contains(OPTIMIZED_BUILD_OPTION_LONG) && !wasBuildEverRun()) {
|
||||
throw new PropertyException(Messages.optimizedUsedForFirstStartup());
|
||||
}
|
||||
|
||||
IncludeOptions options = getIncludeOptions(cliArgs, abstractCommand, abstractCommand.getName());
|
||||
|
||||
if (!options.includeBuildTime && !options.includeRuntime) {
|
||||
|
@ -391,8 +369,7 @@ public class Picocli {
|
|||
ConfigValue configValue = Configuration.getConfigValue(mapper.getFrom());
|
||||
String configValueStr = configValue.getValue();
|
||||
|
||||
// don't consider missing or anything below standard env properties
|
||||
if (configValueStr == null || configValue.getConfigSourceOrdinal() < 300) {
|
||||
if (configValueStr == null || !isUserModifiable(configValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -455,14 +432,19 @@ public class Picocli {
|
|||
}
|
||||
}
|
||||
|
||||
private static boolean isUserModifiable(ConfigValue configValue) {
|
||||
// This could check as low as SysPropConfigSource DEFAULT_ORDINAL, which is 400
|
||||
// for now we won't validate these as it's not expected for the user to specify options via system properties
|
||||
return configValue.getConfigSourceOrdinal() >= KeycloakPropertiesConfigSource.PROPERTIES_FILE_ORDINAL;
|
||||
}
|
||||
|
||||
private static void checkSpiOptions(IncludeOptions options, final List<String> ignoredBuildTime,
|
||||
final List<String> ignoredRunTime) {
|
||||
String kcSpiPrefix = NS_KEYCLOAK_PREFIX + "spi";
|
||||
for (String key : Configuration.getConfig().getPropertyNames()) {
|
||||
if (!key.startsWith(kcSpiPrefix)) {
|
||||
if (!key.startsWith(PropertyMappers.KC_SPI_PREFIX)) {
|
||||
continue;
|
||||
}
|
||||
boolean buildTimeOption = key.endsWith("-provider") || key.endsWith("-provider-default") || key.endsWith("-enabled");
|
||||
boolean buildTimeOption = PropertyMappers.isSpiBuildTimeProperty(key);
|
||||
|
||||
ConfigValue configValue = Configuration.getConfigValue(key);
|
||||
String configValueStr = configValue.getValue();
|
||||
|
@ -558,124 +540,59 @@ public class Picocli {
|
|||
String.join("\n", properties)), outWriter);
|
||||
}
|
||||
|
||||
private static boolean hasConfigChanges(CommandLine cmdCommand) {
|
||||
Optional<String> currentProfile = ofNullable(org.keycloak.common.util.Environment.getProfile());
|
||||
Optional<String> persistedProfile = getBuildTimeProperty("kc.profile");
|
||||
|
||||
if (!persistedProfile.orElse("").equals(currentProfile.orElse(""))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (String propertyName : getConfig().getPropertyNames()) {
|
||||
// only check keycloak build-time properties
|
||||
if (!isBuildTimeProperty(propertyName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ConfigValue configValue = getConfig().getConfigValue(propertyName);
|
||||
|
||||
if (configValue == null || configValue.getConfigSourceName() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// try to resolve any property set using profiles
|
||||
if (propertyName.startsWith("%")) {
|
||||
propertyName = propertyName.substring(propertyName.indexOf('.') + 1);
|
||||
}
|
||||
|
||||
String persistedValue = getBuildTimeProperty(propertyName).orElse("");
|
||||
String runtimeValue = getRuntimeProperty(propertyName).orElse(null);
|
||||
|
||||
// compare only the relevant options for this command, as not all options might be set for this command
|
||||
if (cmdCommand.getCommand() instanceof AbstractCommand) {
|
||||
AbstractCommand abstractCommand = cmdCommand.getCommand();
|
||||
PropertyMapper<?> mapper = PropertyMappers.getMapper(propertyName);
|
||||
if (mapper != null) {
|
||||
if (!abstractCommand.getOptionCategories().contains(mapper.getCategory())) {
|
||||
continue;
|
||||
}
|
||||
public static Properties getNonPersistedBuildTimeOptions() {
|
||||
Properties properties = new Properties();
|
||||
// TODO: could get only non-persistent property names
|
||||
Configuration.getPropertyNames().forEach(name -> {
|
||||
boolean quarkus = false;
|
||||
PropertyMapper<?> mapper = PropertyMappers.getMapper(name);
|
||||
if (mapper != null) {
|
||||
if (!mapper.isBuildTime()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (runtimeValue == null && isNotBlank(persistedValue)) {
|
||||
PropertyMapper<?> mapper = PropertyMappers.getMapper(propertyName);
|
||||
|
||||
if (mapper != null && persistedValue.equals(Option.getDefaultValueString(mapper.getDefaultValue().orElse(null)))) {
|
||||
// same as default
|
||||
continue;
|
||||
name = mapper.getFrom();
|
||||
if (properties.containsKey(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// probably because it was unset
|
||||
return true;
|
||||
} else if (name.startsWith(MicroProfileConfigProvider.NS_QUARKUS)) {
|
||||
// TODO: this is not correct - we are including runtime properties here, but at least they
|
||||
// are already coming from a file
|
||||
quarkus = true;
|
||||
} else if (!PropertyMappers.isSpiBuildTimeProperty(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// changes to a single property is enough to indicate changes to configuration
|
||||
if (!persistedValue.equals(runtimeValue)) {
|
||||
return true;
|
||||
ConfigValue value = Configuration.getNonPersistedConfigValue(name);
|
||||
if (value.getValue() == null || value.getConfigSourceName() == null
|
||||
|| (quarkus && !value.getConfigSourceName().equals(QuarkusPropertiesConfigSource.NAME))) {
|
||||
// only persist build options resolved from config sources and not default values
|
||||
return;
|
||||
}
|
||||
// since we're presisting all quarkus values, this may leak some runtime information - we don't want
|
||||
// to capture expanded expressions that may be referencing environment variables
|
||||
String stringValue = value.getValue();
|
||||
if (quarkus && value.getRawValue() != null) {
|
||||
stringValue = value.getRawValue();
|
||||
}
|
||||
properties.put(name, stringValue);
|
||||
});
|
||||
|
||||
// the following should be ignored when output the optimized check message
|
||||
// they are either not set by the user, or not properly initialized
|
||||
|
||||
for (File jar : getProviderFiles().values()) {
|
||||
properties.put(String.format(KC_PROVIDER_FILE_PREFIX + "%s.last-modified", jar.getName()), String.valueOf(jar.lastModified()));
|
||||
}
|
||||
|
||||
//check for defined quarkus raw build properties for UserStorageProvider extensions
|
||||
if (QuarkusPropertiesConfigSource.getConfigurationFile() != null) {
|
||||
Optional<ConfigSource> quarkusPropertiesConfigSource = getConfig().getConfigSource(QuarkusPropertiesConfigSource.NAME);
|
||||
|
||||
if (quarkusPropertiesConfigSource.isPresent()) {
|
||||
Map<String, String> foundQuarkusBuildProperties = findSupportedRawQuarkusBuildProperties(quarkusPropertiesConfigSource.get().getProperties().entrySet());
|
||||
|
||||
//only check if buildProps are found in quarkus properties file.
|
||||
if (!foundQuarkusBuildProperties.isEmpty()) {
|
||||
Optional<ConfigSource> persistedConfigSource = getConfig().getConfigSource(PersistedConfigSource.NAME);
|
||||
|
||||
if(persistedConfigSource.isPresent()) {
|
||||
for(String key : foundQuarkusBuildProperties.keySet()) {
|
||||
if (notContainsKey(persistedConfigSource.get(), key)) {
|
||||
//if persisted cs does not contain raw quarkus key from quarkus.properties, assume build is needed as the key is new.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//if it contains the key, check if the value actually changed from the persisted one.
|
||||
return hasAtLeastOneChangedBuildProperty(foundQuarkusBuildProperties, persistedConfigSource.get().getProperties().entrySet());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!Environment.isRebuildCheck()) {
|
||||
// not auto-build (e.g.: start without optimized option) but a regular build to create an optimized server image
|
||||
Configuration.markAsOptimized(properties);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
String profile = org.keycloak.common.util.Environment.getProfile();
|
||||
properties.put(org.keycloak.common.util.Environment.PROFILE, profile);
|
||||
properties.put(LaunchMode.current().getProfileKey(), profile);
|
||||
|
||||
private static boolean hasAtLeastOneChangedBuildProperty(Map<String, String> foundQuarkusBuildProperties, Set<Map.Entry<String, String>> persistedEntries) {
|
||||
for(Map.Entry<String, String> persistedEntry : persistedEntries) {
|
||||
if (foundQuarkusBuildProperties.containsKey(persistedEntry.getKey())) {
|
||||
return isChangedValue(foundQuarkusBuildProperties, persistedEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean notContainsKey(ConfigSource persistedConfigSource, String key) {
|
||||
return !persistedConfigSource.getProperties().containsKey(key);
|
||||
}
|
||||
|
||||
private static Map<String, String> findSupportedRawQuarkusBuildProperties(Set<Map.Entry<String, String>> entries) {
|
||||
Pattern buildTimePattern = Pattern.compile(QuarkusPropertiesConfigSource.QUARKUS_DATASOURCE_BUILDTIME_REGEX);
|
||||
Map<String, String> result = new HashMap<>();
|
||||
|
||||
for(Map.Entry<String, String> entry : entries) {
|
||||
if (buildTimePattern.matcher(entry.getKey()).matches()) {
|
||||
result.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isChangedValue(Map<String, String> foundQuarkusBuildProps, Map.Entry<String, String> persistedEntry) {
|
||||
return !foundQuarkusBuildProps.get(persistedEntry.getKey()).equals(persistedEntry.getValue());
|
||||
}
|
||||
|
||||
private static boolean isProviderKey(String key) {
|
||||
return key.startsWith("kc.provider.file");
|
||||
return properties;
|
||||
}
|
||||
|
||||
public CommandLine createCommandLine(Consumer<CommandSpec> consumer) {
|
||||
|
@ -740,12 +657,9 @@ public class Picocli {
|
|||
}
|
||||
|
||||
private static void addCommandOptions(List<String> cliArgs, CommandLine command) {
|
||||
if (command != null && command.getCommand() instanceof AbstractCommand ac) {
|
||||
if (command != null && command.getCommand() instanceof AbstractCommand) {
|
||||
IncludeOptions options = getIncludeOptions(cliArgs, command.getCommand(), command.getCommandName());
|
||||
|
||||
// set current parsed command
|
||||
Environment.setParsedCommand(ac);
|
||||
|
||||
if (!options.includeBuildTime && !options.includeRuntime) {
|
||||
return;
|
||||
}
|
||||
|
@ -938,48 +852,51 @@ public class Picocli {
|
|||
return args;
|
||||
}
|
||||
|
||||
private static void checkChangesInBuildOptionsDuringAutoBuild() {
|
||||
if (Configuration.isOptimized()) {
|
||||
List<PropertyMapper<?>> buildOptions = stream(Configuration.getPropertyNames(true).spliterator(), false)
|
||||
.sorted()
|
||||
.map(PropertyMappers::getMapper)
|
||||
.filter(Objects::nonNull).collect(Collectors.toList());
|
||||
private static void checkChangesInBuildOptionsDuringAutoBuild(PrintWriter out) {
|
||||
StringBuilder options = new StringBuilder();
|
||||
|
||||
if (buildOptions.isEmpty()) {
|
||||
return;
|
||||
var current = getNonPersistedBuildTimeOptions();
|
||||
var persisted = Configuration.getRawPersistedProperties();
|
||||
|
||||
// TODO: order is not well defined here
|
||||
|
||||
current.forEach((key, value) -> {
|
||||
String persistedValue = persisted.get(key);
|
||||
if (!value.equals(persistedValue)) {
|
||||
optionChanged(options, (String)key, persistedValue, (String)value);
|
||||
}
|
||||
});
|
||||
|
||||
StringBuilder options = new StringBuilder();
|
||||
|
||||
for (PropertyMapper<?> mapper : buildOptions) {
|
||||
String newValue = ofNullable(getCurrentBuiltTimeProperty(mapper.getFrom()))
|
||||
.map(ConfigValue::getValue)
|
||||
.orElse("<unset>");
|
||||
String currentValue = getRawPersistedProperty(mapper.getFrom()).get();
|
||||
|
||||
if (newValue.equals(currentValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = mapper.getOption().getKey();
|
||||
|
||||
options.append("\n\t- ")
|
||||
.append(name).append("=").append(currentValue)
|
||||
.append(" > ")
|
||||
.append(name).append("=").append(newValue);
|
||||
persisted.forEach((key, value) -> {
|
||||
if (current.get(key) == null) {
|
||||
optionChanged(options, key, value, null);
|
||||
}
|
||||
});
|
||||
|
||||
if (options.length() > 0) {
|
||||
System.out.println(
|
||||
Ansi.AUTO.string(
|
||||
new StringBuilder("@|bold,red ")
|
||||
.append("The previous optimized build will be overridden with the following build options:")
|
||||
.append(options)
|
||||
.append("\nTo avoid that, run the 'build' command again and then start the optimized server instance using the '--optimized' flag.")
|
||||
.append("|@").toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
if (options.length() > 0) {
|
||||
out.println(
|
||||
Ansi.AUTO.string(
|
||||
new StringBuilder("@|bold,red ")
|
||||
.append("The previous optimized build will be overridden with the following build options:")
|
||||
.append(options)
|
||||
.append("\nTo avoid that, run the 'build' command again and then start the optimized server instance using the '--optimized' flag.")
|
||||
.append("|@").toString()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static void optionChanged(StringBuilder options, String key, String oldValue, String newValue) {
|
||||
// the assumption here is that no build time options need mask handling
|
||||
boolean isIgnored = !key.startsWith(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX)
|
||||
|| key.startsWith(KC_PROVIDER_FILE_PREFIX) || key.equals(Configuration.KC_OPTIMIZED)
|
||||
|| key.equals(org.keycloak.common.util.Environment.PROFILE);
|
||||
if (!isIgnored) {
|
||||
key = key.substring(3);
|
||||
options.append("\n\t- ").append(key).append("=")
|
||||
.append(Optional.ofNullable(oldValue).orElse("<unset>")).append(" > ")
|
||||
.append(key).append("=")
|
||||
.append(Optional.ofNullable(newValue).orElse("<unset>"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,10 +19,6 @@ package org.keycloak.quarkus.runtime.cli.command;
|
|||
|
||||
import org.keycloak.config.OptionCategory;
|
||||
import org.keycloak.quarkus.runtime.Environment;
|
||||
import org.keycloak.quarkus.runtime.KeycloakMain;
|
||||
import org.keycloak.quarkus.runtime.Messages;
|
||||
import org.keycloak.quarkus.runtime.cli.ExecutionExceptionHandler;
|
||||
import org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource;
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.HostnameV2PropertyMappers;
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.HttpPropertyMappers;
|
||||
|
||||
|
@ -46,10 +42,6 @@ public abstract class AbstractStartCommand extends AbstractCommand implements Ru
|
|||
HostnameV2PropertyMappers.validateConfig();
|
||||
validateConfig();
|
||||
|
||||
if (ConfigArgsConfigSource.getAllCliArgs().contains(OPTIMIZED_BUILD_OPTION_LONG) && !wasBuildEverRun()) {
|
||||
executionError(spec.commandLine(), Messages.optimizedUsedForFirstStartup());
|
||||
}
|
||||
|
||||
picocli.start(cmd);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,15 +21,14 @@ import static org.keycloak.config.ClassLoaderOptions.QUARKUS_REMOVED_ARTIFACTS_P
|
|||
import static org.keycloak.quarkus.runtime.Environment.getHomePath;
|
||||
import static org.keycloak.quarkus.runtime.Environment.isDevProfile;
|
||||
import static org.keycloak.quarkus.runtime.cli.Picocli.println;
|
||||
import static org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource.getAllCliArgs;
|
||||
|
||||
import io.quarkus.runtime.LaunchMode;
|
||||
|
||||
import org.keycloak.config.OptionCategory;
|
||||
import org.keycloak.quarkus.runtime.Environment;
|
||||
import org.keycloak.quarkus.runtime.Messages;
|
||||
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||
|
||||
import io.quarkus.bootstrap.runner.QuarkusEntryPoint;
|
||||
import io.quarkus.bootstrap.runner.RunnerClassLoader;
|
||||
|
||||
import io.smallrye.config.ConfigValue;
|
||||
|
@ -68,7 +67,10 @@ public final class Build extends AbstractCommand implements Runnable {
|
|||
|
||||
@Override
|
||||
public void run() {
|
||||
exitWithErrorIfDevProfileIsSetAndNotStartDev();
|
||||
if (org.keycloak.common.util.Environment.getProfile() == null) {
|
||||
Environment.setProfile(Environment.PROD_PROFILE_VALUE);
|
||||
}
|
||||
exitWithErrorIfDevProfileIsSet();
|
||||
|
||||
System.setProperty("quarkus.launch.rebuild", "true");
|
||||
validateConfig();
|
||||
|
@ -94,7 +96,7 @@ public final class Build extends AbstractCommand implements Runnable {
|
|||
|
||||
private static void configureBuildClassLoader() {
|
||||
// ignored artifacts must be set prior to starting re-augmentation
|
||||
Optional.ofNullable(Configuration.getCurrentBuiltTimeProperty(QUARKUS_REMOVED_ARTIFACTS_PROPERTY))
|
||||
Optional.ofNullable(Configuration.getNonPersistedConfigValue(QUARKUS_REMOVED_ARTIFACTS_PROPERTY))
|
||||
.map(ConfigValue::getValue)
|
||||
.ifPresent(s -> System.setProperty(QUARKUS_REMOVED_ARTIFACTS_PROPERTY, s));
|
||||
}
|
||||
|
@ -110,9 +112,14 @@ public final class Build extends AbstractCommand implements Runnable {
|
|||
return super.getOptionCategories();
|
||||
}
|
||||
|
||||
private void exitWithErrorIfDevProfileIsSetAndNotStartDev() {
|
||||
if (Environment.isDevProfile() && !getAllCliArgs().contains(StartDev.NAME)) {
|
||||
executionError(spec.commandLine(), Messages.devProfileNotAllowedError(NAME));
|
||||
private void exitWithErrorIfDevProfileIsSet() {
|
||||
if (Environment.isDevProfile()) {
|
||||
String cmd = Environment.getParsedCommand().map(AbstractCommand::getName).orElse(getName());
|
||||
// we allow start-dev, and import|export|bootstrap-admin --profile=dev
|
||||
// but not start --profile=dev, nor build --profile=dev
|
||||
if (Start.NAME.equals(cmd) || Build.NAME.equals(cmd)) {
|
||||
executionError(spec.commandLine(), Messages.devProfileNotAllowedError(cmd));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ package org.keycloak.quarkus.runtime.cli.command;
|
|||
import picocli.AutoComplete;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
@Command(name = "completion",
|
||||
@Command(name = Completion.NAME,
|
||||
header = "Generate bash/zsh completion script for ${ROOT-COMMAND-NAME:-the root command of this command}.",
|
||||
description = {
|
||||
"",
|
||||
|
@ -29,4 +29,6 @@ import picocli.CommandLine.Command;
|
|||
"",
|
||||
" source <(${PARENT-COMMAND-FULL-NAME:-$PARENTCOMMAND} ${COMMAND-NAME})"})
|
||||
public class Completion extends AutoComplete.GenerateCompletion {
|
||||
|
||||
public static final String NAME = "completion";
|
||||
}
|
||||
|
|
|
@ -17,17 +17,13 @@
|
|||
|
||||
package org.keycloak.quarkus.runtime.cli.command;
|
||||
|
||||
import static org.keycloak.quarkus.runtime.Environment.getCurrentOrPersistedProfile;
|
||||
import static org.keycloak.quarkus.runtime.Environment.setProfile;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getConfigValue;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getPropertyNames;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getRuntimeProperty;
|
||||
import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers.maskValue;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
@ -60,23 +56,18 @@ public final class ShowConfig extends AbstractCommand implements Runnable {
|
|||
|
||||
@Override
|
||||
public void run() {
|
||||
System.setProperty("kc.show.config", filter);
|
||||
String configArgs = System.getProperty("kc.show.config");
|
||||
String profile = Optional.ofNullable(getCurrentOrPersistedProfile()).orElse(Environment.PROD_PROFILE_VALUE);
|
||||
setProfile(profile);
|
||||
String profile = Environment.updateProfile(true);
|
||||
|
||||
Map<String, Set<String>> properties = getPropertiesByGroup();
|
||||
printRunTimeConfig(properties, profile);
|
||||
|
||||
if (configArgs.equalsIgnoreCase("all")) {
|
||||
if (filter.equalsIgnoreCase("all")) {
|
||||
spec.commandLine().getOut().println("Quarkus Configuration:");
|
||||
properties.get(MicroProfileConfigProvider.NS_QUARKUS).stream().sorted()
|
||||
.forEachOrdered(this::printProperty);
|
||||
}
|
||||
|
||||
if (!Boolean.getBoolean("kc.show.config.runtime")) {
|
||||
Quarkus.asyncExit(0);
|
||||
}
|
||||
Quarkus.asyncExit(0);
|
||||
}
|
||||
|
||||
private void printRunTimeConfig(Map<String, Set<String>> properties, String profile) {
|
||||
|
@ -119,12 +110,8 @@ public final class ShowConfig extends AbstractCommand implements Runnable {
|
|||
|
||||
PropertyMapper<?> mapper = PropertyMappers.getMapper(property);
|
||||
|
||||
if (mapper == null) {
|
||||
if (configValue.getSourceName().equals("SysPropConfigSource") && !allowedSystemPropertyKeys.contains(property)) {
|
||||
return; // most system properties are internally used, and not relevant during show-config
|
||||
}
|
||||
} else if (mapper.isRunTime()) {
|
||||
value = getRuntimeProperty(property).orElse(value);
|
||||
if (mapper == null && configValue.getSourceName().equals("SysPropConfigSource") && !allowedSystemPropertyKeys.contains(property)) {
|
||||
return; // most system properties are internally used, and not relevant during show-config
|
||||
}
|
||||
|
||||
value = maskValue(configValue.getName(), value, configValue.getConfigSourceName());
|
||||
|
|
|
@ -17,9 +17,7 @@
|
|||
|
||||
package org.keycloak.quarkus.runtime.cli.command;
|
||||
|
||||
import static org.keycloak.quarkus.runtime.Environment.setProfile;
|
||||
import static org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.OPTIMIZED_BUILD_OPTION_LONG;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getRawPersistedProperty;
|
||||
|
||||
import org.keycloak.quarkus.runtime.Environment;
|
||||
import org.keycloak.quarkus.runtime.Messages;
|
||||
|
@ -27,8 +25,6 @@ import org.keycloak.quarkus.runtime.Messages;
|
|||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.Command;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Command(name = Start.NAME,
|
||||
header = "Start the server.",
|
||||
description = {
|
||||
|
@ -52,24 +48,12 @@ public final class Start extends AbstractStartCommand implements Runnable {
|
|||
|
||||
@Override
|
||||
protected void doBeforeRun() {
|
||||
devProfileNotAllowedError();
|
||||
}
|
||||
|
||||
private void devProfileNotAllowedError() {
|
||||
if (isDevProfileNotAllowed()) {
|
||||
Environment.updateProfile(true);
|
||||
if (Environment.isDevProfile()) {
|
||||
executionError(spec.commandLine(), Messages.devProfileNotAllowedError(NAME));
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isDevProfileNotAllowed() {
|
||||
Optional<String> currentProfile = Optional.ofNullable(org.keycloak.common.util.Environment.getProfile());
|
||||
Optional<String> persistedProfile = getRawPersistedProperty("kc.profile");
|
||||
|
||||
setProfile(currentProfile.orElse(persistedProfile.orElse("prod")));
|
||||
|
||||
return Environment.isDevProfile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean includeRuntime() {
|
||||
return true;
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package org.keycloak.quarkus.runtime.configuration;
|
||||
|
||||
import static org.keycloak.quarkus.runtime.Environment.getProfileOrDefault;
|
||||
import static org.keycloak.quarkus.runtime.cli.Picocli.ARG_PREFIX;
|
||||
|
||||
import java.util.Map;
|
||||
|
@ -28,7 +27,6 @@ import io.smallrye.config.ConfigValue;
|
|||
import io.smallrye.config.SmallRyeConfig;
|
||||
|
||||
import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
|
||||
import org.eclipse.microprofile.config.spi.ConfigSource;
|
||||
import org.keycloak.config.Option;
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper;
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
|
||||
|
@ -43,7 +41,7 @@ public final class Configuration {
|
|||
|
||||
public static final char OPTION_PART_SEPARATOR_CHAR = '-';
|
||||
public static final String OPTION_PART_SEPARATOR = String.valueOf(OPTION_PART_SEPARATOR_CHAR);
|
||||
private static final String KC_OPTIMIZED = NS_KEYCLOAK_PREFIX + "optimized";
|
||||
public static final String KC_OPTIMIZED = NS_KEYCLOAK_PREFIX + "optimized";
|
||||
|
||||
private Configuration() {
|
||||
|
||||
|
@ -79,34 +77,9 @@ public final class Configuration {
|
|||
return (SmallRyeConfig) ConfigProviderResolver.instance().getConfig();
|
||||
}
|
||||
|
||||
public static Optional<String> getBuildTimeProperty(String name) {
|
||||
Optional<String> value = getRawPersistedProperty(name);
|
||||
|
||||
if (value.isEmpty()) {
|
||||
PropertyMapper<?> mapper = PropertyMappers.getMapper(name);
|
||||
|
||||
if (mapper != null) {
|
||||
value = getRawPersistedProperty(mapper.getFrom());
|
||||
|
||||
if (value.isEmpty() && mapper.getTo() != null) {
|
||||
value = getRawPersistedProperty(mapper.getTo());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value.isEmpty()) {
|
||||
String profile = org.keycloak.common.util.Environment.getProfile();
|
||||
|
||||
if (profile == null) {
|
||||
profile = getConfig().getRawValue(org.keycloak.common.util.Environment.PROFILE);
|
||||
}
|
||||
|
||||
value = getRawPersistedProperty("%" + profile + "." + name);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw persisted keycloak properties will match the resolved value of what was originally specified by the user
|
||||
*/
|
||||
public static Optional<String> getRawPersistedProperty(String name) {
|
||||
return Optional.ofNullable(PersistedConfigSource.getInstance().getValue(name));
|
||||
}
|
||||
|
@ -170,26 +143,6 @@ public final class Configuration {
|
|||
return mapper.getTo() == null ? mapper.getFrom() : mapper.getTo();
|
||||
}
|
||||
|
||||
public static Optional<String> getRuntimeProperty(String name) {
|
||||
for (ConfigSource configSource : getConfig().getConfigSources()) {
|
||||
if (PersistedConfigSource.NAME.equals(configSource.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String value = getValue(configSource, name);
|
||||
|
||||
if (value == null) {
|
||||
value = getValue(configSource, getMappedPropertyName(name));
|
||||
}
|
||||
|
||||
if (value != null) {
|
||||
return Optional.of(value);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static String toEnvVarFormat(String key) {
|
||||
return replaceNonAlphanumericByUnderscores(key).toUpperCase();
|
||||
}
|
||||
|
@ -233,16 +186,6 @@ public final class Configuration {
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String getValue(ConfigSource configSource, String name) {
|
||||
String value = configSource.getValue("%".concat(getProfileOrDefault("prod").concat(".").concat(name)));
|
||||
|
||||
if (value == null) {
|
||||
value = configSource.getValue(name);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static boolean isOptimized() {
|
||||
return Configuration.getRawPersistedProperty(KC_OPTIMIZED).isPresent();
|
||||
}
|
||||
|
@ -251,7 +194,7 @@ public final class Configuration {
|
|||
properties.put(Configuration.KC_OPTIMIZED, Boolean.TRUE.toString());
|
||||
}
|
||||
|
||||
public static ConfigValue getCurrentBuiltTimeProperty(String name) {
|
||||
public static ConfigValue getNonPersistedConfigValue(String name) {
|
||||
return PersistedConfigSource.getInstance().runWithDisabled(() -> getConfigValue(name));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ import io.smallrye.config.AbstractLocationConfigSourceLoader;
|
|||
import io.smallrye.config.PropertiesConfigSource;
|
||||
import io.smallrye.config.common.utils.ConfigSourceUtil;
|
||||
|
||||
import static org.keycloak.common.util.StringPropertyReplacer.replaceProperties;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getMappedPropertyName;
|
||||
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK;
|
||||
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX;
|
||||
|
@ -51,6 +50,8 @@ import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvi
|
|||
*/
|
||||
public class KeycloakPropertiesConfigSource extends AbstractLocationConfigSourceLoader {
|
||||
|
||||
public static final int PROPERTIES_FILE_ORDINAL = 475;
|
||||
|
||||
private static final Pattern DOT_SPLIT = Pattern.compile("\\.");
|
||||
private static final String KEYCLOAK_CONFIG_FILE_ENV = "KC_CONFIG_FILE";
|
||||
private static final String KEYCLOAK_CONF_FILE = "keycloak.conf";
|
||||
|
@ -124,7 +125,7 @@ public class KeycloakPropertiesConfigSource extends AbstractLocationConfigSource
|
|||
}
|
||||
|
||||
public List<ConfigSource> getConfigSources(final ClassLoader classLoader, Path configFile) {
|
||||
return loadConfigSources(configFile.toUri().toString(), 450, classLoader);
|
||||
return loadConfigSources(configFile.toUri().toString(), PROPERTIES_FILE_ORDINAL, classLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
|
||||
package org.keycloak.quarkus.runtime.configuration;
|
||||
|
||||
import static java.lang.Boolean.parseBoolean;
|
||||
import static org.keycloak.quarkus.runtime.configuration.Configuration.getRawPersistedProperty;
|
||||
import static org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider.NS_QUARKUS;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -36,7 +34,6 @@ import org.eclipse.microprofile.config.spi.ConfigSourceProvider;
|
|||
import org.keycloak.quarkus.runtime.Environment;
|
||||
|
||||
import io.smallrye.config.AbstractLocationConfigSourceLoader;
|
||||
import io.smallrye.config.ConfigValue;
|
||||
import io.smallrye.config.PropertiesConfigSource;
|
||||
import io.smallrye.config.common.utils.ConfigSourceUtil;
|
||||
|
||||
|
@ -46,23 +43,8 @@ import io.smallrye.config.common.utils.ConfigSourceUtil;
|
|||
public final class QuarkusPropertiesConfigSource extends AbstractLocationConfigSourceLoader implements ConfigSourceProvider {
|
||||
|
||||
private static final String FILE_NAME = "quarkus.properties";
|
||||
public static final String QUARKUS_PROPERTY_ENABLED = "kc.quarkus-properties-enabled";
|
||||
public static final String NAME = "QuarkusProperties";
|
||||
|
||||
//for auto-build working with multiple datasources
|
||||
public static final String QUARKUS_DATASOURCE_BUILDTIME_REGEX = "^quarkus\\.datasource\\.[A-Za-z0-9\\-_]+\\.(db-kind|jdbc\\.driver|jdbc\\.transactions|jdbc\\.enable-metrics)$";
|
||||
|
||||
public static boolean isSameSource(ConfigValue value) {
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// workaround for https://github.com/smallrye/smallrye-config/issues/1207
|
||||
// replace by the following line when fixed:
|
||||
// return NAME.equals(value.getConfigSourceName());
|
||||
return value.getConfigSourceName() != null && value.getConfigSourceName().endsWith(FILE_NAME);
|
||||
}
|
||||
|
||||
public static Path getConfigurationFile() {
|
||||
String homeDir = Environment.getHomeDir();
|
||||
|
||||
|
@ -77,6 +59,8 @@ public final class QuarkusPropertiesConfigSource extends AbstractLocationConfigS
|
|||
return null;
|
||||
}
|
||||
|
||||
private boolean loadingFile;
|
||||
|
||||
@Override
|
||||
protected String[] getFileExtensions() {
|
||||
return new String[] { "properties" };
|
||||
|
@ -84,10 +68,11 @@ public final class QuarkusPropertiesConfigSource extends AbstractLocationConfigS
|
|||
|
||||
@Override
|
||||
protected ConfigSource loadConfigSource(URL url, int ordinal) throws IOException {
|
||||
return new PropertiesConfigSource(ConfigSourceUtil.urlToMap(url), FILE_NAME, ordinal) {
|
||||
String name = loadingFile ? NAME : (NAME + " " + url);
|
||||
return new PropertiesConfigSource(ConfigSourceUtil.urlToMap(url), name, ordinal) {
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -102,7 +87,7 @@ public final class QuarkusPropertiesConfigSource extends AbstractLocationConfigS
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<ConfigSource> getConfigSources(final ClassLoader classLoader) {
|
||||
public synchronized List<ConfigSource> getConfigSources(final ClassLoader classLoader) {
|
||||
List<ConfigSource> configSources = new ArrayList<>();
|
||||
|
||||
configSources.addAll(loadConfigSources("META-INF/services/" + FILE_NAME, 450, classLoader));
|
||||
|
@ -110,7 +95,12 @@ public final class QuarkusPropertiesConfigSource extends AbstractLocationConfigS
|
|||
Path configFile = getConfigurationFile();
|
||||
|
||||
if (configFile != null) {
|
||||
configSources.addAll(loadConfigSources(configFile.toUri().toString(), 500, classLoader));
|
||||
loadingFile = true;
|
||||
try {
|
||||
configSources.addAll(loadConfigSources(configFile.toUri().toString(), KeycloakPropertiesConfigSource.PROPERTIES_FILE_ORDINAL, classLoader));
|
||||
} finally {
|
||||
loadingFile = false;
|
||||
}
|
||||
}
|
||||
|
||||
return configSources;
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.util.stream.Stream;
|
|||
|
||||
import io.smallrye.config.ConfigSourceInterceptorContext;
|
||||
import io.smallrye.config.ConfigValue;
|
||||
import io.smallrye.config.ConfigValue.ConfigValueBuilder;
|
||||
|
||||
import org.keycloak.config.DeprecatedMetadata;
|
||||
import org.keycloak.config.Option;
|
||||
|
@ -131,9 +132,12 @@ public class PropertyMapper<T> {
|
|||
}
|
||||
|
||||
if (config != null && config.getValue() != null) {
|
||||
config = transformValue(name, config.getValue(), context, config.getConfigSourceName(), parentValue);
|
||||
config = transformValue(name, config, context, parentValue);
|
||||
} else {
|
||||
config = transformValue(name, this.option.getDefaultValue().map(Option::getDefaultValueString).orElse(null), context, null, false);
|
||||
String defaultValue = this.option.getDefaultValue().map(Option::getDefaultValueString).orElse(null);
|
||||
config = transformValue(name, new ConfigValueBuilder().withName(name)
|
||||
.withValue(defaultValue).withRawValue(defaultValue).build(),
|
||||
context, false);
|
||||
}
|
||||
|
||||
if (config != null) {
|
||||
|
@ -232,24 +236,27 @@ public class PropertyMapper<T> {
|
|||
return option.getDeprecatedMetadata();
|
||||
}
|
||||
|
||||
private ConfigValue transformValue(String name, String value, ConfigSourceInterceptorContext context, String configSourceName, boolean parentValue) {
|
||||
private ConfigValue transformValue(String name, ConfigValue configValue, ConfigSourceInterceptorContext context, boolean parentValue) {
|
||||
String value = configValue.getValue();
|
||||
String mappedValue = value;
|
||||
|
||||
boolean mapped = false;
|
||||
var theMapper = parentValue ? this.parentMapper : this.mapper;
|
||||
if (theMapper != null && (!name.equals(getFrom()) || parentValue)) {
|
||||
mappedValue = theMapper.apply(value, context);
|
||||
mapped = true;
|
||||
}
|
||||
|
||||
if (value == null && mappedValue == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ConfigValue.builder()
|
||||
.withName(name)
|
||||
.withValue(mappedValue)
|
||||
.withRawValue(value)
|
||||
.withConfigSourceName(configSourceName)
|
||||
.build();
|
||||
if (!mapped && name.equals(configValue.getName())) {
|
||||
return configValue;
|
||||
}
|
||||
|
||||
// by unsetting the ordinal this will not be seen as directly modified by the user
|
||||
return configValue.from().withValue(mappedValue).withRawValue(value).withConfigSourceOrdinal(0).build();
|
||||
}
|
||||
|
||||
private ConfigValue convertValue(ConfigValue configValue) {
|
||||
|
|
|
@ -13,7 +13,6 @@ import org.keycloak.quarkus.runtime.cli.PropertyException;
|
|||
import org.keycloak.quarkus.runtime.cli.command.AbstractCommand;
|
||||
import org.keycloak.quarkus.runtime.cli.command.Build;
|
||||
import org.keycloak.quarkus.runtime.cli.command.ShowConfig;
|
||||
import org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource;
|
||||
import org.keycloak.quarkus.runtime.configuration.DisabledMappersInterceptor;
|
||||
import org.keycloak.quarkus.runtime.configuration.PersistedConfigSource;
|
||||
|
||||
|
@ -78,32 +77,10 @@ public final class PropertyMappers {
|
|||
return getMapperOrDefault(name, PropertyMapper.IDENTITY).getConfigValue(name, context);
|
||||
}
|
||||
|
||||
public static boolean isBuildTimeProperty(String name) {
|
||||
if (isFeaturesBuildTimeProperty(name) || isSpiBuildTimeProperty(name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final PropertyMapper<?> mapper = getMapperOrDefault(name, null);
|
||||
boolean isBuildTimeProperty = mapper == null ? false : mapper.isBuildTime();
|
||||
|
||||
return isBuildTimeProperty
|
||||
&& !"kc.version".equals(name)
|
||||
&& !"kc.home.dir".equals(name)
|
||||
&& !"kc.config.file".equals(name)
|
||||
&& !org.keycloak.common.util.Environment.PROFILE.equals(name)
|
||||
&& !"kc.show.config".equals(name)
|
||||
&& !"kc.show.config.runtime".equals(name)
|
||||
&& !"kc.config-file".equals(name);
|
||||
}
|
||||
|
||||
public static boolean isSpiBuildTimeProperty(String name) {
|
||||
return name.startsWith(KC_SPI_PREFIX) && (name.endsWith("-provider") || name.endsWith("-enabled") || name.endsWith("-provider-default"));
|
||||
}
|
||||
|
||||
private static boolean isFeaturesBuildTimeProperty(String name) {
|
||||
return name.startsWith("kc.features");
|
||||
}
|
||||
|
||||
public static Map<OptionCategory, List<PropertyMapper<?>>> getRuntimeMappers() {
|
||||
return MAPPERS.getRuntimeMappers();
|
||||
}
|
||||
|
|
|
@ -21,13 +21,19 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.keycloak.quarkus.runtime.Environment;
|
||||
import org.keycloak.quarkus.runtime.cli.Picocli;
|
||||
import org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource;
|
||||
import org.keycloak.quarkus.runtime.configuration.test.AbstractConfigurationTest;
|
||||
|
@ -45,6 +51,8 @@ public class PicocliTest extends AbstractConfigurationTest {
|
|||
final StringWriter out = new StringWriter();
|
||||
SmallRyeConfig config;
|
||||
int exitCode = Integer.MAX_VALUE;
|
||||
boolean reaug;
|
||||
private Properties buildProps;
|
||||
|
||||
String getErrString() {
|
||||
return normalize(err);
|
||||
|
@ -76,10 +84,6 @@ public class PicocliTest extends AbstractConfigurationTest {
|
|||
this.exitCode = exitCode;
|
||||
}
|
||||
|
||||
protected int runReAugmentationIfNeeded(List<String> cliArgs, CommandLine cmd, CommandLine currentCommand) {
|
||||
throw new AssertionError("Should not reaugment");
|
||||
};
|
||||
|
||||
@Override
|
||||
public void parseAndRun(List<String> cliArgs) {
|
||||
config = createConfig();
|
||||
|
@ -93,7 +97,8 @@ public class PicocliTest extends AbstractConfigurationTest {
|
|||
|
||||
@Override
|
||||
public void build() throws Throwable {
|
||||
// skip
|
||||
reaug = true;
|
||||
this.buildProps = getNonPersistedBuildTimeOptions();
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -255,4 +260,112 @@ public class PicocliTest extends AbstractConfigurationTest {
|
|||
assertThat(nonRunningPicocli.getOutString(), containsString("The following run time options were found, but will be ignored during build time: kc.spi-something-pass"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failBuildDev() {
|
||||
NonRunningPicocli nonRunningPicocli = pseudoLaunch("--profile=dev", "build");
|
||||
assertThat(nonRunningPicocli.getErrString(), containsString("You can not 'build' the server in development mode."));
|
||||
assertEquals(CommandLine.ExitCode.SOFTWARE, nonRunningPicocli.exitCode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failStartBuildDev() {
|
||||
NonRunningPicocli nonRunningPicocli = pseudoLaunch("--profile=dev", "start");
|
||||
assertThat(nonRunningPicocli.getErrString(), containsString("You can not 'start' the server in development mode."));
|
||||
assertEquals(CommandLine.ExitCode.SOFTWARE, nonRunningPicocli.exitCode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failIfOptimizedUsedForFirstStartupExport() {
|
||||
NonRunningPicocli nonRunningPicocli = pseudoLaunch("export", "--optimized", "--dir=data");
|
||||
assertEquals(CommandLine.ExitCode.USAGE, nonRunningPicocli.exitCode);
|
||||
assertThat(nonRunningPicocli.getErrString(), containsString("The '--optimized' flag was used for first ever server start."));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReaugFromProdToDev() {
|
||||
build("build");
|
||||
|
||||
Environment.setRebuildCheck(); // will be reset by the system properties logic
|
||||
NonRunningPicocli nonRunningPicocli = pseudoLaunch("start-dev", "--hostname=name", "--http-enabled=true");
|
||||
assertEquals(CommandLine.ExitCode.OK, nonRunningPicocli.exitCode);
|
||||
assertTrue(nonRunningPicocli.reaug);
|
||||
assertEquals("dev", nonRunningPicocli.buildProps.getProperty(org.keycloak.common.util.Environment.PROFILE));;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a fake build to setup the state of the persisted build properties
|
||||
*/
|
||||
private void build(String... args) {
|
||||
if (Stream.of(args).anyMatch("start-dev"::equals)) {
|
||||
Environment.setRebuildCheck(); // auto-build
|
||||
}
|
||||
NonRunningPicocli nonRunningPicocli = pseudoLaunch(args);
|
||||
assertTrue(nonRunningPicocli.reaug);
|
||||
assertEquals(CommandLine.ExitCode.OK, nonRunningPicocli.exitCode);
|
||||
onAfter();
|
||||
addPersistedConfigValues((Map)nonRunningPicocli.buildProps);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReaugFromProdToDevExport() {
|
||||
build("build");
|
||||
|
||||
Environment.setRebuildCheck(); // will be reset by the system properties logic
|
||||
NonRunningPicocli nonRunningPicocli = pseudoLaunch("--profile=dev", "export", "--file=file");
|
||||
assertEquals(CommandLine.ExitCode.OK, nonRunningPicocli.exitCode);
|
||||
assertTrue(nonRunningPicocli.reaug);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoReaugFromProdToExport() {
|
||||
build("build");
|
||||
|
||||
Environment.setRebuildCheck(); // will be reset by the system properties logic
|
||||
NonRunningPicocli nonRunningPicocli = pseudoLaunch("export", "--file=file");
|
||||
assertEquals(CommandLine.ExitCode.OK, nonRunningPicocli.exitCode);
|
||||
assertFalse(nonRunningPicocli.reaug);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReaugFromDevToProd() {
|
||||
build("start-dev");
|
||||
|
||||
Environment.setRebuildCheck(); // will be reset by the system properties logic
|
||||
NonRunningPicocli nonRunningPicocli = pseudoLaunch("start", "--hostname=name", "--http-enabled=true");
|
||||
assertEquals(CommandLine.ExitCode.OK, nonRunningPicocli.exitCode);
|
||||
assertTrue(nonRunningPicocli.reaug);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoReaugFromDevToDevExport() {
|
||||
build("start-dev");
|
||||
|
||||
Environment.setRebuildCheck(); // will be reset by the system properties logic
|
||||
NonRunningPicocli nonRunningPicocli = pseudoLaunch("--profile=dev", "export", "--file=file");
|
||||
assertEquals(CommandLine.ExitCode.OK, nonRunningPicocli.exitCode);
|
||||
assertFalse(nonRunningPicocli.reaug);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReaugFromDevToProdExport() {
|
||||
build("start-dev");
|
||||
|
||||
Environment.setRebuildCheck(); // will be reset by the system properties logic
|
||||
NonRunningPicocli nonRunningPicocli = pseudoLaunch("export", "--file=file");
|
||||
assertEquals(CommandLine.ExitCode.OK, nonRunningPicocli.exitCode);
|
||||
assertTrue(nonRunningPicocli.reaug);
|
||||
assertEquals("prod", nonRunningPicocli.buildProps.getProperty(org.keycloak.common.util.Environment.PROFILE));;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptimizedReaugmentationMessage() {
|
||||
build("build");
|
||||
|
||||
Environment.setRebuildCheck(); // will be reset by the system properties logic
|
||||
NonRunningPicocli nonRunningPicocli = pseudoLaunch("start", "--features=docker", "--hostname=name", "--http-enabled=true");
|
||||
assertEquals(CommandLine.ExitCode.OK, nonRunningPicocli.exitCode);
|
||||
assertThat(nonRunningPicocli.getOutString(), containsString("features=<unset> > features=docker"));
|
||||
assertTrue(nonRunningPicocli.reaug);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,8 @@ import io.quarkus.runtime.configuration.ConfigUtils;
|
|||
import io.smallrye.config.ConfigValue;
|
||||
import io.smallrye.config.SmallRyeConfig;
|
||||
import io.smallrye.config.SmallRyeConfigProviderResolver;
|
||||
import io.smallrye.config.ConfigValue.ConfigValueBuilder;
|
||||
|
||||
import org.eclipse.microprofile.config.ConfigProvider;
|
||||
import org.eclipse.microprofile.config.spi.ConfigProviderResolver;
|
||||
import org.junit.After;
|
||||
|
@ -30,6 +32,7 @@ import org.keycloak.quarkus.runtime.configuration.ConfigArgsConfigSource;
|
|||
import org.keycloak.quarkus.runtime.configuration.Configuration;
|
||||
import org.keycloak.quarkus.runtime.configuration.KeycloakConfigSourceProvider;
|
||||
import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
|
||||
import org.keycloak.quarkus.runtime.configuration.PersistedConfigSource;
|
||||
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
@ -113,6 +116,7 @@ public abstract class AbstractConfigurationTest {
|
|||
SmallRyeConfigProviderResolver.class.cast(ConfigProviderResolver.instance()).releaseConfig(ConfigProvider.getConfig());
|
||||
PropertyMappers.reset();
|
||||
ConfigArgsConfigSource.setCliArgs();
|
||||
PersistedConfigSource.getInstance().getConfigValueProperties().clear();
|
||||
}
|
||||
|
||||
protected Config.Scope initConfig(String... scope) {
|
||||
|
@ -153,4 +157,9 @@ public abstract class AbstractConfigurationTest {
|
|||
protected void assertExternalConfig(Map<String, String> expectedValues) {
|
||||
expectedValues.forEach(this::assertExternalConfig);
|
||||
}
|
||||
|
||||
protected static void addPersistedConfigValues(Map<String, String> values) {
|
||||
var configValueProps = PersistedConfigSource.getInstance().getConfigValueProperties();
|
||||
values.forEach((k, v) -> configValueProps.put(k, new ConfigValueBuilder().withName(k).withValue(v).build()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
package org.keycloak.quarkus.runtime.configuration.test;
|
||||
|
||||
|
||||
import org.junit.Test;
|
||||
import org.keycloak.quarkus.runtime.configuration.QuarkusPropertiesConfigSource;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ConfigRegExPatternMatchingTest {
|
||||
|
||||
@Test
|
||||
public void quarkusPropertyMultipleDatasourcePatternTest(){
|
||||
Pattern p = Pattern.compile(QuarkusPropertiesConfigSource.QUARKUS_DATASOURCE_BUILDTIME_REGEX);
|
||||
assertTrue(p.matcher("quarkus.datasource.user.jdbc.transactions").matches());
|
||||
assertTrue(p.matcher("quarkus.datasource.user-store.jdbc.enable-metrics").matches());
|
||||
assertTrue(p.matcher("quarkus.datasource.user12_store.db-kind").matches());
|
||||
assertTrue(p.matcher("quarkus.datasource.user12_-__--store.db-kind").matches());
|
||||
assertFalse(p.matcher("quarkus.datasource.user-store.db-username").matches());
|
||||
assertFalse(p.matcher("quarkus.datasource.user-store.db-kin").matches());
|
||||
}
|
||||
}
|
|
@ -22,7 +22,6 @@ import static org.junit.Assert.assertNull;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
import static org.keycloak.quarkus.runtime.Environment.isWindows;
|
||||
|
||||
import java.nio.file.FileSystem;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
|
|
|
@ -22,6 +22,8 @@ import static org.hamcrest.CoreMatchers.not;
|
|||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -52,6 +54,7 @@ public class QuarkusPropertiesAutoBuildDistTest {
|
|||
@BeforeStartDistribution(EnableAdditionalConsoleHandler.class)
|
||||
@Launch({ "start" })
|
||||
@Order(2)
|
||||
@Disabled(value = "We don't properly differentiate between quarkus runtime and build time properties")
|
||||
void testQuarkusRuntimePropDoesNotTriggerReAug(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
cliResult.assertNoBuild();
|
||||
|
@ -63,6 +66,7 @@ public class QuarkusPropertiesAutoBuildDistTest {
|
|||
@BeforeStartDistribution(DisableAdditionalConsoleHandler.class)
|
||||
@Launch({ "start" })
|
||||
@Order(3)
|
||||
@Disabled(value = "We don't properly differentiate between quarkus runtime and build time properties")
|
||||
void testNoReAugAfterChangingRuntimeProperty(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
cliResult.assertNoBuild();
|
||||
|
@ -82,6 +86,7 @@ public class QuarkusPropertiesAutoBuildDistTest {
|
|||
@BeforeStartDistribution(ChangeAdditionalDatasourceUsername.class)
|
||||
@Launch({ "start" })
|
||||
@Order(5)
|
||||
@Disabled(value = "We don't properly differentiate between quarkus runtime and build time properties")
|
||||
void testNoReAugForAdditionalDatasourceRuntimeProperty(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
cliResult.assertNoBuild();
|
||||
|
|
|
@ -100,6 +100,7 @@ public class QuarkusPropertiesDistTest {
|
|||
@BeforeStartDistribution(UpdateConsoleHandlerFromQuarkusProps.class)
|
||||
@Launch({"start", "--http-enabled=true", "--hostname-strict=false"})
|
||||
@Order(6)
|
||||
@Disabled(value = "We don't properly differentiate between quarkus runtime and build time properties")
|
||||
void testRuntimePropFromQuarkusPropsIsAppliedWithoutRebuild(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
assertThat(cliResult.getOutput(), not(containsString("Keycloak is the best")));
|
||||
|
|
|
@ -28,7 +28,9 @@ 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.utils.KeycloakDistribution;
|
||||
import org.keycloak.it.utils.RawKeycloakDistribution;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
@ -87,4 +89,17 @@ public class StartDevCommandDistTest {
|
|||
cliResult.assertStartedDevMode();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testStartDevThenImportRebuild(KeycloakDistribution dist) throws Exception {
|
||||
RawKeycloakDistribution rawDist = dist.unwrap(RawKeycloakDistribution.class);
|
||||
CLIResult result = rawDist.run("start-dev");
|
||||
assertTrue(result.getErrorOutput().isEmpty(), result.getErrorOutput());
|
||||
|
||||
File target = new File("./target");
|
||||
|
||||
// feature change should trigger a build
|
||||
result = rawDist.run("--profile=dev", "export", "--features=docker", "--dir=" + target.getAbsolutePath());
|
||||
result.assertMessage("Updating the configuration and installing your custom providers, if any. Please wait.");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue