[KEYCLOAK-16126] - Windows support
This commit is contained in:
parent
a63814da67
commit
f6fe88b587
5 changed files with 171 additions and 3 deletions
|
@ -1,4 +1,17 @@
|
||||||
@echo off
|
@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" (
|
if "%OS%" == "Windows_NT" (
|
||||||
set "DIRNAME=%~dp0%"
|
set "DIRNAME=%~dp0%"
|
||||||
|
@ -6,4 +19,92 @@ if "%OS%" == "Windows_NT" (
|
||||||
set DIRNAME=.\
|
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
|
|
@ -20,6 +20,9 @@ package org.keycloak.cli;
|
||||||
import static org.keycloak.cli.Picocli.error;
|
import static org.keycloak.cli.Picocli.error;
|
||||||
import static org.keycloak.cli.Picocli.println;
|
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 org.keycloak.configuration.KeycloakConfigSourceProvider;
|
||||||
|
|
||||||
import io.quarkus.bootstrap.runner.QuarkusEntryPoint;
|
import io.quarkus.bootstrap.runner.QuarkusEntryPoint;
|
||||||
|
@ -30,6 +33,10 @@ import picocli.CommandLine.Model.CommandSpec;
|
||||||
import picocli.CommandLine.Option;
|
import picocli.CommandLine.Option;
|
||||||
import picocli.CommandLine.Spec;
|
import picocli.CommandLine.Spec;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Command(name = "keycloak",
|
@Command(name = "keycloak",
|
||||||
usageHelpWidth = 150,
|
usageHelpWidth = 150,
|
||||||
header = "Keycloak - Open Source Identity and Access Management\n\nFind more information at: https://www.keycloak.org/%n",
|
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) {
|
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");
|
System.setProperty("quarkus.launch.rebuild", "true");
|
||||||
println(spec.commandLine(), "Updating the configuration and installing your custom providers, if any. Please wait.");
|
println(spec.commandLine(), "Updating the configuration and installing your custom providers, if any. Please wait.");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
beforeReaugmentationOnWindows();
|
||||||
QuarkusEntryPoint.main();
|
QuarkusEntryPoint.main();
|
||||||
println(spec.commandLine(), "Server configuration updated and persisted. Run the following command to review the configuration:\n");
|
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");
|
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",
|
@Command(name = "start-dev",
|
||||||
description = "%nStart the server in development mode.%n",
|
description = "%nStart the server in development mode.%n",
|
||||||
mixinStandardHelpOptions = true,
|
mixinStandardHelpOptions = true,
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
package org.keycloak.configuration;
|
package org.keycloak.configuration;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -76,7 +77,7 @@ class Database {
|
||||||
@Override
|
@Override
|
||||||
public String apply(String alias) {
|
public String apply(String alias) {
|
||||||
if ("h2-file".equalsIgnoreCase(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:}";
|
return "jdbc:h2:mem:keycloakdb${kc.db.url.properties:}";
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.util;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.SystemUtils;
|
||||||
import org.keycloak.configuration.Configuration;
|
import org.keycloak.configuration.Configuration;
|
||||||
|
|
||||||
public final class Environment {
|
public final class Environment {
|
||||||
|
@ -38,6 +39,9 @@ public final class Environment {
|
||||||
return "java -jar $KEYCLOAK_HOME/lib/quarkus-run.jar";
|
return "java -jar $KEYCLOAK_HOME/lib/quarkus-run.jar";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isWindows()) {
|
||||||
|
return "kc.bat";
|
||||||
|
}
|
||||||
return "kc.sh";
|
return "kc.sh";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,4 +82,8 @@ public final class Environment {
|
||||||
public static boolean isDevMode() {
|
public static boolean isDevMode() {
|
||||||
return "dev".equalsIgnoreCase(getProfile());
|
return "dev".equalsIgnoreCase(getProfile());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isWindows() {
|
||||||
|
return SystemUtils.IS_OS_WINDOWS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.provider.quarkus;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -198,7 +199,7 @@ public class ConfigurationTest {
|
||||||
System.setProperty("kc.config.args", "--db=h2-file");
|
System.setProperty("kc.config.args", "--db=h2-file");
|
||||||
SmallRyeConfig config = createConfig();
|
SmallRyeConfig config = createConfig();
|
||||||
assertEquals(QuarkusH2Dialect.class.getName(), config.getConfigValue("quarkus.hibernate-orm.dialect").getValue());
|
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.db.url.properties", "?test=test&test1=test1");
|
||||||
System.setProperty("kc.config.args", "--db=mariadb");
|
System.setProperty("kc.config.args", "--db=mariadb");
|
||||||
|
|
Loading…
Reference in a new issue