[KEYCLOAK-16126] - Windows support

This commit is contained in:
Pedro Igor 2020-11-09 17:31:48 -03:00 committed by Marek Posolda
parent a63814da67
commit f6fe88b587
5 changed files with 171 additions and 3 deletions

View file

@ -1,4 +1,17 @@
@echo off
rem -------------------------------------------------------------------------
rem Keycloak Startup Script
rem -------------------------------------------------------------------------
@if not "%ECHO%" == "" echo %ECHO%
setlocal
rem Get the program name before using shift as the command modify the variable ~nx0
if "%OS%" == "Windows_NT" (
set "PROGNAME=%~nx0%"
) else (
set "PROGNAME=kc.bat"
)
if "%OS%" == "Windows_NT" (
set "DIRNAME=%~dp0%"
@ -6,4 +19,92 @@ if "%OS%" == "Windows_NT" (
set DIRNAME=.\
)
java -Dkeycloak.theme.dir=%DIRNAME%\..\themes -cp "%DIRNAME%\..\providers\*;%DIRNAME%\..\lib\keycloak-runner.jar" io.quarkus.runner.GeneratedMain %*
set "SERVER_OPTS=-Dkc.home.dir=%DIRNAME%.. -Djboss.server.config.dir=%DIRNAME%..\conf -Dkeycloak.theme.dir=%DIRNAME%..\themes -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
set DEBUG_MODE=false
set DEBUG_PORT_VAR=8787
rem Read command-line args, the ~ removes the quotes from the parameter
:READ-ARGS
set "KEY=%~1"
if "%KEY%" == "" (
goto MAIN
)
if "%KEY%" == "--debug" (
set "DEBUG_MODE=true"
set "DEBUG_PORT_VAR=%~2"
if "%DEBUG_PORT_VAR%" == "" (
set DEBUG_PORT_VAR=8787
)
shift
shift
goto READ-ARGS
)
if not "%KEY:~0,2%"=="--" if "%KEY:~0,1%"=="-" (
set "SERVER_OPTS=%SERVER_OPTS% %KEY%=%~2"
shift
)
if not "%KEY:~0,2%"=="--" if not "%KEY:~0,1%"=="-" (
set "CONFIG_ARGS=%CONFIG_ARGS% %KEY%"
)
if "%KEY:~0,2%"=="--" (
if "%~2"=="" (
set "CONFIG_ARGS=%CONFIG_ARGS% %KEY%"
) else (
set "CONFIG_ARGS=%CONFIG_ARGS% %KEY%=%~2%"
)
shift
)
shift
goto READ-ARGS
:MAIN
if not "x%JAVA_OPTS%" == "x" (
echo "JAVA_OPTS already set in environment; overriding default settings with values: %JAVA_OPTS%"
) else (
set "JAVA_OPTS=-Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m -Djava.net.preferIPv4Stack=true"
)
if NOT "x%DEBUG%" == "x" (
set "DEBUG_MODE=%DEBUG%
)
if NOT "x%DEBUG_PORT%" == "x" (
set DEBUG_PORT_VAR=%DEBUG_PORT%
)
rem Set debug settings if not already set
if "%DEBUG_MODE%" == "true" (
echo "%JAVA_OPTS%" | findstr /I "\-agentlib:jdwp" > nul
if errorlevel == 1 (
set "JAVA_OPTS=%JAVA_OPTS% -agentlib:jdwp=transport=dt_socket,address=%DEBUG_PORT_VAR%,server=y,suspend=n"
) else (
echo Debug already enabled in JAVA_OPTS, ignoring --debug argument
)
)
rem Setup Keycloak specific properties
set "JAVA_OPTS=-Dprogram.name=%PROGNAME% %JAVA_OPTS%"
if "x%JAVA_HOME%" == "x" (
set JAVA=java
echo JAVA_HOME is not set. Unexpected results may occur.
echo Set JAVA_HOME to the directory of your local JDK to avoid this message.
) else (
if not exist "%JAVA_HOME%" (
echo JAVA_HOME "%JAVA_HOME%" path doesn't exist
goto END
) else (
if not exist "%JAVA_HOME%\bin\java.exe" (
echo "%JAVA_HOME%\bin\java.exe" does not exist
goto END
)
set "JAVA=%JAVA_HOME%\bin\java"
)
)
set "CLASSPATH_OPTS=%DIRNAME%..\lib\quarkus-run.jar;%DIRNAME%..\lib\lib\main\*.*"
"%JAVA%" %JAVA_OPTS% %SERVER_OPTS% -cp %CLASSPATH_OPTS% io.quarkus.bootstrap.runner.QuarkusEntryPoint %CONFIG_ARGS%
:END

View file

@ -20,6 +20,9 @@ package org.keycloak.cli;
import static org.keycloak.cli.Picocli.error;
import static org.keycloak.cli.Picocli.println;
import io.quarkus.bootstrap.runner.ClassLoadingResource;
import io.quarkus.bootstrap.runner.JarResource;
import io.quarkus.bootstrap.runner.RunnerClassLoader;
import org.keycloak.configuration.KeycloakConfigSourceProvider;
import io.quarkus.bootstrap.runner.QuarkusEntryPoint;
@ -30,6 +33,10 @@ import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Option;
import picocli.CommandLine.Spec;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.Map;
@Command(name = "keycloak",
usageHelpWidth = 150,
header = "Keycloak - Open Source Identity and Access Management\n\nFind more information at: https://www.keycloak.org/%n",
@ -73,7 +80,9 @@ public class MainCommand {
public void reAugment(@Option(names = "--verbose", description = "Print out more details when running this command.", required = false) Boolean verbose) {
System.setProperty("quarkus.launch.rebuild", "true");
println(spec.commandLine(), "Updating the configuration and installing your custom providers, if any. Please wait.");
try {
beforeReaugmentationOnWindows();
QuarkusEntryPoint.main();
println(spec.commandLine(), "Server configuration updated and persisted. Run the following command to review the configuration:\n");
println(spec.commandLine(), "\t" + Environment.getCommand() + " show-config\n");
@ -82,6 +91,54 @@ public class MainCommand {
}
}
private void beforeReaugmentationOnWindows() throws Exception {
// On Windows, files generated during re-augmentation are locked and can't be re-created.
// To workaround this behavior, we close these files as they are not needed during re-augmentation,
// but when actually running the application.
// See KEYCLOAK-16218
if (Environment.isWindows()) {
Field resourcesMapField = null;
try {
RunnerClassLoader cl = (RunnerClassLoader) Thread.currentThread().getContextClassLoader();
resourcesMapField = cl.getClass().getDeclaredField("resourceDirectoryMap");
resourcesMapField.setAccessible(true);
Map<String, ClassLoadingResource[]> resourcesMap = (Map<String, ClassLoadingResource[]>) resourcesMapField.get(cl);
for (ClassLoadingResource[] resources : resourcesMap.values()) {
for (ClassLoadingResource resource : resources) {
if (resource instanceof JarResource) {
Field jarPath = null;
try {
JarResource jr = (JarResource) resource;
jarPath = jr.getClass().getDeclaredField("jarPath");
jarPath.setAccessible(true);
Path path = (Path) jarPath.get(jr);
if (path.getFileName().endsWith("generated-bytecode.jar")) {
jr.close();
}
} finally {
if (jarPath != null) {
jarPath.setAccessible(false);
}
}
}
}
}
} finally {
if (resourcesMapField != null) {
resourcesMapField.setAccessible(false);
}
}
}
}
@Command(name = "start-dev",
description = "%nStart the server in development mode.%n",
mixinStandardHelpOptions = true,

View file

@ -17,6 +17,7 @@
package org.keycloak.configuration;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
@ -76,7 +77,7 @@ class Database {
@Override
public String apply(String alias) {
if ("h2-file".equalsIgnoreCase(alias)) {
return "jdbc:h2:file:${kc.home.dir:${kc.db.url.path:~}}/${kc.data.dir:data}/keycloakdb${kc.db.url.properties:;;AUTO_SERVER=TRUE}";
return "jdbc:h2:file:${kc.home.dir:${kc.db.url.path:~}}" + File.separator + "${kc.data.dir:data}" + File.separator + "keycloakdb${kc.db.url.properties:;;AUTO_SERVER=TRUE}";
}
return "jdbc:h2:mem:keycloakdb${kc.db.url.properties:}";
}

View file

@ -19,6 +19,7 @@ package org.keycloak.util;
import java.util.Optional;
import org.apache.commons.lang3.SystemUtils;
import org.keycloak.configuration.Configuration;
public final class Environment {
@ -38,6 +39,9 @@ public final class Environment {
return "java -jar $KEYCLOAK_HOME/lib/quarkus-run.jar";
}
if (isWindows()) {
return "kc.bat";
}
return "kc.sh";
}
@ -78,4 +82,8 @@ public final class Environment {
public static boolean isDevMode() {
return "dev".equalsIgnoreCase(getProfile());
}
public static boolean isWindows() {
return SystemUtils.IS_OS_WINDOWS;
}
}

View file

@ -19,6 +19,7 @@ package org.keycloak.provider.quarkus;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
@ -198,7 +199,7 @@ public class ConfigurationTest {
System.setProperty("kc.config.args", "--db=h2-file");
SmallRyeConfig config = createConfig();
assertEquals(QuarkusH2Dialect.class.getName(), config.getConfigValue("quarkus.hibernate-orm.dialect").getValue());
assertEquals("jdbc:h2:file:test-dir/data/keycloakdb;;test=test;test1=test1", config.getConfigValue("quarkus.datasource.jdbc.url").getValue());
assertEquals("jdbc:h2:file:test-dir" + File.separator + "data" + File.separator + "keycloakdb;;test=test;test1=test1", config.getConfigValue("quarkus.datasource.jdbc.url").getValue());
System.setProperty("kc.db.url.properties", "?test=test&test1=test1");
System.setProperty("kc.config.args", "--db=mariadb");