[KEYCLOAK-14255] - More improvements to CLI
This commit is contained in:
parent
6596811d5d
commit
04415d34ea
9 changed files with 132 additions and 61 deletions
|
@ -46,7 +46,7 @@ do
|
|||
break
|
||||
;;
|
||||
*)
|
||||
if [[ $1 = --* || ! $1 =~ ^-.* ]]; then
|
||||
if [[ $1 = -* || ! $1 =~ ^-.* ]]; then
|
||||
CONFIG_ARGS="$CONFIG_ARGS $1"
|
||||
else
|
||||
SERVER_OPTS="$SERVER_OPTS $1"
|
||||
|
|
|
@ -151,7 +151,7 @@ class KeycloakProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
recorder.setBuildTimeProperties(properties, Environment.isRebuild(), KeycloakRecorder.getConfig().getRawValue("kc.config.args"));
|
||||
recorder.validateAndSetBuildTimeProperties(properties, Environment.isRebuild(), KeycloakRecorder.getConfig().getRawValue("kc.config.args"));
|
||||
|
||||
recorder.showConfig();
|
||||
}
|
||||
|
|
|
@ -38,6 +38,17 @@ public class KeycloakMain {
|
|||
|
||||
if (args.length != 0) {
|
||||
CommandLine cmd = new CommandLine(createCommandSpec());
|
||||
|
||||
cmd.setExecutionExceptionHandler(new CommandLine.IExecutionExceptionHandler() {
|
||||
@Override
|
||||
public int handleExecutionException(Exception ex, CommandLine commandLine,
|
||||
CommandLine.ParseResult parseResult) {
|
||||
commandLine.getErr().println(ex.getMessage());
|
||||
commandLine.usage(commandLine.getErr());
|
||||
return commandLine.getCommandSpec().exitCodeOnExecutionException();
|
||||
}
|
||||
});
|
||||
|
||||
List<String> argsList = new LinkedList<>(Arrays.asList(args));
|
||||
|
||||
try {
|
||||
|
@ -48,12 +59,15 @@ public class KeycloakMain {
|
|||
argsList.add(0, "start");
|
||||
}
|
||||
} catch (CommandLine.UnmatchedArgumentException e) {
|
||||
if (!cmd.getParseResult().hasSubcommand()) {
|
||||
if (!cmd.getParseResult().hasSubcommand() && argsList.get(0).startsWith("--")) {
|
||||
argsList.add(0, "start");
|
||||
} else {
|
||||
cmd.getErr().println(e.getMessage());
|
||||
System.exit(CommandLine.ExitCode.SOFTWARE);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
cmd.getErr().println(e.getMessage());
|
||||
System.exit(CommandLine.ExitCode.SOFTWARE);
|
||||
}
|
||||
|
||||
System.exit(cmd.execute(argsList.toArray(new String[argsList.size()])));
|
||||
|
|
|
@ -44,15 +44,16 @@ public class MainCommand {
|
|||
@Spec
|
||||
CommandSpec spec;
|
||||
|
||||
@Option(names = { "--help" }, usageHelp = true, hidden = true)
|
||||
@Option(names = { "--help" }, description = "This help message.", usageHelp = true)
|
||||
boolean help;
|
||||
|
||||
@Option(names = { "--version" }, versionHelp = true, hidden = true)
|
||||
@Option(names = { "--version" }, description = "Show version information", versionHelp = true)
|
||||
boolean version;
|
||||
|
||||
@Option(names = "--profile", arity = "1", description = "Set the profile. Use 'dev' profile to enable development mode.", scope = CommandLine.ScopeType.INHERIT)
|
||||
public void setProfile(String profile) {
|
||||
System.setProperty("kc.profile", profile);
|
||||
System.setProperty("kc.profile", "dev");
|
||||
System.setProperty("quarkus.profile", "dev");
|
||||
}
|
||||
|
||||
@Option(names = "--config-file", arity = "1", description = "Set the path to a configuration file.", paramLabel = "<path>", scope = CommandLine.ScopeType.INHERIT)
|
||||
|
@ -85,6 +86,7 @@ public class MainCommand {
|
|||
parameterListHeading = "Available Commands%n")
|
||||
public void startDev() {
|
||||
System.setProperty("kc.profile", "dev");
|
||||
System.setProperty("quarkus.profile", "dev");
|
||||
start();
|
||||
}
|
||||
|
||||
|
@ -162,9 +164,11 @@ public class MainCommand {
|
|||
public void start(
|
||||
@CommandLine.Parameters(paramLabel = "show-config", arity = "0..1",
|
||||
description = "Print out the configuration options when starting the server.") String showConfig) {
|
||||
if (showConfig != null) {
|
||||
if ("show-config".equals(showConfig)) {
|
||||
System.setProperty("kc.show.config.runtime", Boolean.TRUE.toString());
|
||||
System.setProperty("kc.show.config", "all");
|
||||
} else if (showConfig != null) {
|
||||
throw new CommandLine.UnmatchedArgumentException(spec.commandLine(), "Invalid argument: " + showConfig);
|
||||
}
|
||||
start();
|
||||
}
|
||||
|
|
|
@ -50,19 +50,23 @@ public final class ShowConfigCommand {
|
|||
.forEachOrdered(ShowConfigCommand::printProperty);
|
||||
|
||||
if (configArgs.equalsIgnoreCase("all")) {
|
||||
properties.get("%").stream()
|
||||
.sorted()
|
||||
.collect(Collectors.groupingBy(s -> s.substring(1, s.indexOf('.'))))
|
||||
.forEach((p, properties1) -> {
|
||||
if (p.equals(profile)) {
|
||||
System.out.printf("Profile \"%s\" Configuration (%s):%n", p,
|
||||
p.equals(profile) ? "current" : "");
|
||||
} else {
|
||||
System.out.printf("Profile \"%s\" Configuration:%n", p);
|
||||
}
|
||||
Set<String> profiles = properties.get("%");
|
||||
|
||||
if (profiles != null) {
|
||||
profiles.stream()
|
||||
.sorted()
|
||||
.collect(Collectors.groupingBy(s -> s.substring(1, s.indexOf('.'))))
|
||||
.forEach((p, properties1) -> {
|
||||
if (p.equals(profile)) {
|
||||
System.out.printf("Profile \"%s\" Configuration (%s):%n", p,
|
||||
p.equals(profile) ? "current" : "");
|
||||
} else {
|
||||
System.out.printf("Profile \"%s\" Configuration:%n", p);
|
||||
}
|
||||
|
||||
properties1.stream().sorted().forEachOrdered(ShowConfigCommand::printProperty);
|
||||
});
|
||||
properties1.stream().sorted().forEachOrdered(ShowConfigCommand::printProperty);
|
||||
});
|
||||
}
|
||||
|
||||
System.out.println("Quarkus Configuration:");
|
||||
properties.get(MicroProfileConfigProvider.NS_QUARKUS).stream().sorted()
|
||||
|
|
|
@ -98,15 +98,11 @@ public class ConfigArgsConfigSource extends PropertiesConfigSource {
|
|||
|
||||
String value;
|
||||
|
||||
if (keyValue.length == 1) {
|
||||
// the argument does not have a value because the key by itself already has a meaning
|
||||
value = Boolean.TRUE.toString();
|
||||
} else if (keyValue.length == 2) {
|
||||
if (keyValue.length == 2) {
|
||||
// the argument has a simple value. Eg.: key=pair
|
||||
value = keyValue[1];
|
||||
} else {
|
||||
// the argument is multivalued. eg.: key=kv1=kv2
|
||||
value = arg.substring(key.length() + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
key = NS_KEYCLOAK_PREFIX + key.substring(2);
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.function.BiFunction;
|
|||
|
||||
import io.smallrye.config.ConfigSourceInterceptorContext;
|
||||
import io.smallrye.config.ConfigValue;
|
||||
import org.keycloak.quarkus.KeycloakRecorder;
|
||||
|
||||
public class PropertyMapper {
|
||||
|
||||
|
@ -60,10 +61,9 @@ public class PropertyMapper {
|
|||
public ConfigValue getOrDefault(String name, ConfigSourceInterceptorContext context, ConfigValue current) {
|
||||
if (current == null) {
|
||||
ConfigValue.builder().withName(name)
|
||||
.withValue(getBuiltTimeProperty(
|
||||
NS_KEYCLOAK_PREFIX + name.substring(NS_KEYCLOAK_PREFIX.length()).replaceAll("\\.", "-"))
|
||||
.orElseGet(() -> getBuiltTimeProperty(name).orElse(null)))
|
||||
.build();
|
||||
.withValue(getBuiltTimeProperty(PropertyMappers.toCLIFormat(name))
|
||||
.orElseGet(() -> getBuiltTimeProperty(name)
|
||||
.orElse(null))).build();
|
||||
}
|
||||
|
||||
return current;
|
||||
|
@ -161,8 +161,8 @@ public class PropertyMapper {
|
|||
}
|
||||
|
||||
public Optional<ConfigValue> getBuiltTimeConfig(String name, ConfigSourceInterceptorContext context) {
|
||||
ConfigValue value = transformValue(getBuiltTimeProperty(name).orElseGet(() -> getBuiltTimeProperty(
|
||||
NS_KEYCLOAK_PREFIX + name.substring(NS_KEYCLOAK_PREFIX.length()).replaceAll("\\.", "-")).orElse(null)), context);
|
||||
ConfigValue value = transformValue(getBuiltTimeProperty(name)
|
||||
.orElseGet(() -> getBuiltTimeProperty(PropertyMappers.toCLIFormat(name)).orElse(null)), context);
|
||||
|
||||
if (value == null) {
|
||||
return Optional.empty();
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.Map;
|
|||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.base.Ascii;
|
||||
import io.quarkus.runtime.configuration.ProfileManager;
|
||||
import io.smallrye.config.ConfigSourceInterceptorContext;
|
||||
import io.smallrye.config.ConfigValue;
|
||||
|
@ -165,4 +166,8 @@ public final class PropertyMappers {
|
|||
return PropertyMapper.MAPPERS.values().stream()
|
||||
.filter(entry -> entry.isBuildTime()).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public static String canonicalFormat(String name) {
|
||||
return name.replaceAll("-", "\\.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,9 @@ package org.keycloak.quarkus;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import io.smallrye.config.ConfigValue;
|
||||
import org.jboss.logging.Logger;
|
||||
|
@ -28,6 +30,7 @@ import org.keycloak.QuarkusKeycloakSessionFactory;
|
|||
import org.keycloak.cli.ShowConfigCommand;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.configuration.MicroProfileConfigProvider;
|
||||
import org.keycloak.configuration.PropertyMapper;
|
||||
import org.keycloak.configuration.PropertyMappers;
|
||||
import org.keycloak.connections.liquibase.FastServiceLocator;
|
||||
import org.keycloak.connections.liquibase.KeycloakLogger;
|
||||
|
@ -106,57 +109,102 @@ public class KeycloakRecorder {
|
|||
QuarkusKeycloakSessionFactory.setInstance(new QuarkusKeycloakSessionFactory(factories, defaultProviders, reaugmented));
|
||||
}
|
||||
|
||||
public void setBuildTimeProperties(Map<String, String> buildTimeProperties, Boolean rebuild, String configArgs) {
|
||||
/**
|
||||
* <p>Validate the build time properties with any property passed during runtime in order to advertise any difference with the
|
||||
* server image state.
|
||||
*
|
||||
* <p>This method also keep the build time properties available at runtime.
|
||||
*
|
||||
*
|
||||
* @param buildTimeProperties the build time properties set when running the last re-augmentation
|
||||
* @param rebuild indicates whether or not the server was re-augmented
|
||||
* @param configArgs the configuration args if provided when the server was re-augmented
|
||||
*/
|
||||
public void validateAndSetBuildTimeProperties(Map<String, String> buildTimeProperties, Boolean rebuild, String configArgs) {
|
||||
BUILD_TIME_PROPERTIES = buildTimeProperties;
|
||||
String configHelpText = configArgs;
|
||||
|
||||
for (String propertyName : getConfig().getPropertyNames()) {
|
||||
if (!propertyName.startsWith(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX)) {
|
||||
// we should only validate if there is a server image and if the property is a runtime property
|
||||
if (!shouldValidate(propertyName, rebuild)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String buildValue = Environment.getBuiltTimeProperty(propertyName).orElseGet(new Supplier<String>() {
|
||||
@Override
|
||||
public String get() {
|
||||
return Environment.getBuiltTimeProperty(PropertyMappers.toCLIFormat(propertyName)).orElse(null);
|
||||
}
|
||||
// try to resolve any property set using profiles
|
||||
if (propertyName.startsWith("%")) {
|
||||
propertyName = propertyName.substring(propertyName.indexOf('.') + 1);
|
||||
}
|
||||
|
||||
String finalPropertyName = propertyName;
|
||||
String buildValue = Environment.getBuiltTimeProperty(PropertyMappers.toCLIFormat(finalPropertyName))
|
||||
.orElseGet(new Supplier<String>() {
|
||||
@Override
|
||||
public String get() {
|
||||
return Environment.getBuiltTimeProperty(finalPropertyName).orElse(null);
|
||||
}
|
||||
});
|
||||
|
||||
ConfigValue value = getConfig().getConfigValue(propertyName);
|
||||
|
||||
// if no value found we try to resolve using the CLI format
|
||||
if (value == null || value.getValue() == null) {
|
||||
value = getConfig().getConfigValue(PropertyMappers.toCLIFormat(propertyName));
|
||||
}
|
||||
|
||||
if (buildValue != null && isRuntimeValue(value) && !buildValue.equalsIgnoreCase(value.getValue())) {
|
||||
if (value.getValue() != null && !value.getValue().equalsIgnoreCase(buildValue)) {
|
||||
if (configHelpText != null) {
|
||||
String currentProp = "--" + PropertyMappers.toCLIFormat(propertyName).substring(3) + "=" + buildValue;
|
||||
String newProp = "--" + PropertyMappers.toCLIFormat(propertyName).substring(3) + "=" + value.getValue();
|
||||
|
||||
if (configHelpText.contains(currentProp)) {
|
||||
LOGGER.warnf("The new value [%s] of the property [%s] in [%s] differs from the value [%s] set into the server image. The new value will override the value set into the server image.", value.getValue(), propertyName, value.getConfigSourceName(), buildValue);
|
||||
configHelpText = configHelpText.replaceAll(currentProp, newProp);
|
||||
} else if (!configHelpText.contains("--" + PropertyMappers.toCLIFormat(propertyName).substring(3))) {
|
||||
configHelpText += newProp;
|
||||
}
|
||||
}
|
||||
} else if (configHelpText != null && rebuild && isRuntimeValue(value)) {
|
||||
String prop = "--" + PropertyMappers.toCLIFormat(propertyName).substring(3) + "=" + value.getValue();
|
||||
if (buildValue != null) {
|
||||
String currentProp =
|
||||
"--" + PropertyMappers.toCLIFormat(propertyName).substring(3) + "=" + buildValue;
|
||||
String newProp =
|
||||
"--" + PropertyMappers.toCLIFormat(propertyName).substring(3) + "=" + value.getValue();
|
||||
|
||||
if (!configHelpText.contains(prop)) {
|
||||
LOGGER.infof("New property [%s] set with value [%s] in [%s]. This property is not persisted into the server image.",
|
||||
propertyName, value.getValue(), value.getConfigSourceName(), buildValue);
|
||||
configHelpText += " " + prop;
|
||||
if (configHelpText.contains(currentProp)) {
|
||||
LOGGER.warnf("The new value [%s] of the property [%s] in [%s] differs from the value [%s] set into the server image. The new value will override the value set into the server image.",
|
||||
value.getValue(), propertyName, value.getConfigSourceName(), buildValue);
|
||||
configHelpText = configHelpText.replaceAll(currentProp, newProp);
|
||||
} else if (!configHelpText
|
||||
.contains("--" + PropertyMappers.toCLIFormat(propertyName).substring(3))) {
|
||||
LOGGER.warnf("The new value [%s] of the property [%s] in [%s] differs from the value [%s] set into the server image. The new value will override the value set into the server image.",
|
||||
value.getValue(), propertyName, value.getConfigSourceName(), buildValue);
|
||||
configHelpText += " " + newProp;
|
||||
}
|
||||
} else if (!BUILD_TIME_PROPERTIES.keySet().stream()
|
||||
.anyMatch(new Predicate<String>() {
|
||||
@Override
|
||||
public boolean test(String s) {
|
||||
return PropertyMappers.canonicalFormat(finalPropertyName)
|
||||
.equalsIgnoreCase(PropertyMappers.canonicalFormat(s));
|
||||
}
|
||||
})) {
|
||||
String prop = "--" + PropertyMappers.toCLIFormat(propertyName).substring(3) + "=" + value.getValue();
|
||||
|
||||
if (!configHelpText.contains(prop)) {
|
||||
LOGGER.warnf("New property [%s] set with value [%s] in [%s]. This property is not persisted into the server image.",
|
||||
propertyName, value.getValue(), value.getConfigSourceName(), buildValue);
|
||||
configHelpText += " " + prop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (configArgs != null && !configArgs.equals(configHelpText)) {
|
||||
LOGGER.infof("Please, run the 'config' command if you want to configure the server image with the new property values:\n\t%s config %s", Environment.getCommand(), String.join(" ", configHelpText.split(",")));
|
||||
LOGGER.warnf("Please, run the 'config' command if you want to persist the new configuration into the server image:\n\n\t%s config %s\n", Environment.getCommand(), String.join(" ", configHelpText.split(",")));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRuntimeValue(ConfigValue value) {
|
||||
String name = value.getName();
|
||||
return value.getValue() != null && !PropertyMappers.isBuildTimeProperty(name)
|
||||
&& !"kc.version".equals(name) && !"kc.config.args".equals(
|
||||
name) && !"kc.home.dir".equals(name);
|
||||
private boolean shouldValidate(String name, boolean rebuild) {
|
||||
return rebuild && name.contains(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX)
|
||||
&& (!PropertyMappers.isBuildTimeProperty(name)
|
||||
&& !"kc.version".equals(name)
|
||||
&& !"kc.config.args".equals(name)
|
||||
&& !"kc.home.dir".equals(name)
|
||||
&& !"kc.config.file".equals(name)
|
||||
&& !"kc.profile".equals(name)
|
||||
&& !"kc.show.config".equals(name)
|
||||
&& !"kc.show.config.runtime".equals(name)
|
||||
&& !PropertyMappers.toCLIFormat("kc.config.file").equals(name));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue