Aligning kc.bat with latest changes to kc.sh

Closes #11185
Closes #13472
This commit is contained in:
Pedro Igor 2022-08-01 14:20:18 -07:00 committed by Hynek Mlnařík
parent ec384702a9
commit 0d3ca438ed
6 changed files with 87 additions and 67 deletions

View file

@ -57,14 +57,15 @@ if not "%KEY:~0,2%"=="--" if "%KEY:~0,2%"=="-D" (
if not "%KEY:~0,2%"=="--" if not "%KEY:~0,1%"=="-" ( if not "%KEY:~0,2%"=="--" if not "%KEY:~0,1%"=="-" (
set "CONFIG_ARGS=%CONFIG_ARGS% %KEY%" set "CONFIG_ARGS=%CONFIG_ARGS% %KEY%"
) )
if "%KEY:~0,2%"=="--" if not "%KEY:~0,2%"=="-D" if "%KEY:~0,1%"=="-" ( if not "%KEY:~0,2%"=="-D" (
if "%~2"=="" ( if "%KEY:~0,1%"=="-" (
set "CONFIG_ARGS=%CONFIG_ARGS% %KEY%" if "%~2"=="" (
) else ( set "CONFIG_ARGS=%CONFIG_ARGS% %KEY%"
set "CONFIG_ARGS=%CONFIG_ARGS% %KEY% %~2%" ) else (
set "CONFIG_ARGS=%CONFIG_ARGS% %KEY% %~2%"
)
shift
) )
shift
) )
shift shift
goto READ-ARGS goto READ-ARGS
@ -129,14 +130,33 @@ set "JAVA_RUN_OPTS=%JAVA_OPTS% -Dkc.home.dir="%DIRNAME%.." -Djboss.server.config
SetLocal EnableDelayedExpansion SetLocal EnableDelayedExpansion
set "ONLY_BUILD_OPTION= build" set "OPTIMIZED_OPTION=--optimized"
set "NO_AUTO_BUILD_OPTION=optimized" set "HELP_LONG_OPTION=--help"
set "BUILD_OPTION= build"
set IS_HELP_SHORT=false
echo "%CONFIG_ARGS%" | findstr /r "\<-h\>" > nul
if not errorlevel == 1 (
set IS_HELP_SHORT=true
)
set START_SERVER=true
if "!CONFIG_ARGS:%OPTIMIZED_OPTION%=!"=="!CONFIG_ARGS!" if "!CONFIG_ARGS:%BUILD_OPTION%=!"=="!CONFIG_ARGS!" if "!CONFIG_ARGS:%HELP_LONG_OPTION%=!"=="!CONFIG_ARGS!" if "%IS_HELP_SHORT%" == "false" (
setlocal enabledelayedexpansion
if "!CONFIG_ARGS:%NO_AUTO_BUILD_OPTION%=!"=="!CONFIG_ARGS!" if "!CONFIG_ARGS:%ONLY_BUILD_OPTION%=!"=="!CONFIG_ARGS!" (
"%JAVA%" -Dkc.config.build-and-exit=true %JAVA_RUN_OPTS% "%JAVA%" -Dkc.config.build-and-exit=true %JAVA_RUN_OPTS%
if not !errorlevel! == 0 (
set START_SERVER=false
)
set "JAVA_RUN_OPTS=-Dkc.config.built=true %JAVA_RUN_OPTS%" set "JAVA_RUN_OPTS=-Dkc.config.built=true %JAVA_RUN_OPTS%"
) )
"%JAVA%" %JAVA_RUN_OPTS% if "%START_SERVER%" == "true" (
"%JAVA%" %JAVA_RUN_OPTS%
)
:END :END

View file

@ -35,7 +35,6 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -43,7 +42,6 @@ import java.util.Properties;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
@ -52,20 +50,22 @@ import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager; import javax.net.ssl.X509TrustManager;
import io.quarkus.deployment.util.FileUtil;
import io.quarkus.fs.util.ZipUtils; import io.quarkus.fs.util.ZipUtils;
import org.apache.commons.io.FileUtils;
import org.keycloak.common.Version; import org.keycloak.common.Version;
import org.keycloak.it.junit5.extension.CLIResult; import org.keycloak.it.junit5.extension.CLIResult;
import org.keycloak.quarkus.runtime.Environment;
import org.keycloak.quarkus.runtime.cli.command.Build; import org.keycloak.quarkus.runtime.cli.command.Build;
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper; import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMapper;
import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers; import org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers;
import static org.keycloak.quarkus.runtime.Environment.LAUNCH_MODE; import static org.keycloak.quarkus.runtime.Environment.LAUNCH_MODE;
import static org.keycloak.quarkus.runtime.Environment.isWindows;
public final class RawKeycloakDistribution implements KeycloakDistribution { public final class RawKeycloakDistribution implements KeycloakDistribution {
private static final int DEFAULT_SHUTDOWN_TIMEOUT_SECONDS = 10;
private Process keycloak; private Process keycloak;
private int exitCode = -1; private int exitCode = -1;
private final Path distPath; private final Path distPath;
@ -128,24 +128,14 @@ public final class RawKeycloakDistribution implements KeycloakDistribution {
public void stop() { public void stop() {
if (isRunning()) { if (isRunning()) {
try { try {
if (Environment.isWindows()) { // On Windows, we need to make sure sub-processes are terminated first
// On Windows, we're executing kc.bat in a runtime as "keycloak", destroyDescendantsOnWindows(keycloak, false);
// so tha java process is an actual child process
// we have to kill first.
killChildProcessesOnWindows(false);
}
keycloak.destroy(); keycloak.destroy();
keycloak.waitFor(10, TimeUnit.SECONDS); keycloak.waitFor(DEFAULT_SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS);
exitCode = keycloak.exitValue(); exitCode = keycloak.exitValue();
} catch (Exception cause) { } catch (Exception cause) {
if (Environment.isWindows()) { destroyDescendantsOnWindows(keycloak, true);
try {
killChildProcessesOnWindows(true);
} catch (Exception e) {
throw new RuntimeException("Failed to stop the server", e);
}
}
keycloak.destroyForcibly(); keycloak.destroyForcibly();
throw new RuntimeException("Failed to stop the server", cause); throw new RuntimeException("Failed to stop the server", cause);
} }
@ -154,19 +144,36 @@ public final class RawKeycloakDistribution implements KeycloakDistribution {
shutdownOutputExecutor(); shutdownOutputExecutor();
} }
private void killChildProcessesOnWindows(boolean isForced) { private void destroyDescendantsOnWindows(Process parent, boolean force) {
for (ProcessHandle childProcessHandle : keycloak.children().collect(Collectors.toList())) { if (!isWindows()) {
CompletableFuture<ProcessHandle> onExit = childProcessHandle.onExit(); return;
if (isForced) { }
childProcessHandle.destroyForcibly();
CompletableFuture allProcesses = CompletableFuture.completedFuture(null);
for (ProcessHandle process : parent.descendants().collect(Collectors.toList())) {
if (force) {
process.destroyForcibly();
} else { } else {
childProcessHandle.destroy(); process.destroy();
} }
//for whatever reason windows doesnt wait for the termination,
// and parent process returns immediately with exitCode 1 but is not exited, leading to allProcesses = CompletableFuture.allOf(allProcesses, process.onExit());
// "failed to start the distribution" bc files that should be deleted }
// are used by another process, so we need this here.
onExit.join(); try {
allProcesses.get(DEFAULT_SHUTDOWN_TIMEOUT_SECONDS, TimeUnit.SECONDS);
} catch (Exception cause) {
throw new RuntimeException("Failed to terminate descendants processes", cause);
}
try {
// TODO: remove this. do not ask why, but on Windows we are here even though the process was previously terminated
// without this pause, tests re-installing dist before tests should fail
// looks like pausing the current thread let windows to cleanup processes?
// more likely it is env dependent
Thread.sleep(500);
} catch (InterruptedException e) {
} }
} }
@ -195,7 +202,7 @@ public final class RawKeycloakDistribution implements KeycloakDistribution {
public String[] getCliArgs(List<String> arguments) { public String[] getCliArgs(List<String> arguments) {
List<String> allArgs = new ArrayList<>(); List<String> allArgs = new ArrayList<>();
if (Environment.isWindows()) { if (isWindows()) {
allArgs.add(distPath.resolve("bin") + File.separator + SCRIPT_CMD_INVOKABLE); allArgs.add(distPath.resolve("bin") + File.separator + SCRIPT_CMD_INVOKABLE);
} else { } else {
allArgs.add(SCRIPT_CMD_INVOKABLE); allArgs.add(SCRIPT_CMD_INVOKABLE);
@ -340,13 +347,7 @@ public final class RawKeycloakDistribution implements KeycloakDistribution {
Path dPath = distRootPath.resolve(distDirName.substring(0, distDirName.lastIndexOf('.'))); Path dPath = distRootPath.resolve(distDirName.substring(0, distDirName.lastIndexOf('.')));
if (!inited || (reCreate || !dPath.toFile().exists())) { if (!inited || (reCreate || !dPath.toFile().exists())) {
FileUtil.deleteDirectory(dPath);
if (!Environment.isWindows()) {
FileUtils.deleteDirectory(dPath.toFile());
} else {
deleteTempFilesOnWindows(dPath);
}
ZipUtils.unzip(distFile.toPath(), distRootPath); ZipUtils.unzip(distFile.toPath(), distRootPath);
} }
@ -363,23 +364,6 @@ public final class RawKeycloakDistribution implements KeycloakDistribution {
} }
} }
private void deleteTempFilesOnWindows(Path dPath) {
if (Files.exists(dPath)) {
try (Stream<Path> walk = Files.walk(dPath)) {
walk.sorted(Comparator.reverseOrder())
.forEach(s -> {
try {
Files.delete(s);
} catch (IOException e) {
throw new RuntimeException("Could not delete temp directory for distribution", e);
}
});
} catch (IOException e) {
throw new RuntimeException("Could not traverse temp directory for distribution to delete files", e);
}
}
}
private void readOutput() { private void readOutput() {
try ( try (
BufferedReader outStream = new BufferedReader(new InputStreamReader(keycloak.getInputStream())); BufferedReader outStream = new BufferedReader(new InputStreamReader(keycloak.getInputStream()));

View file

@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals;
import java.util.List; import java.util.List;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.OS;
import org.keycloak.it.cli.HelpCommandTest; import org.keycloak.it.cli.HelpCommandTest;
import org.keycloak.it.junit5.extension.CLIResult; import org.keycloak.it.junit5.extension.CLIResult;
import org.keycloak.it.junit5.extension.DistributionTest; import org.keycloak.it.junit5.extension.DistributionTest;
@ -35,7 +36,13 @@ public class HelpCommandDistTest extends HelpCommandTest {
public void testHelpDoesNotStartReAugJvm(KeycloakDistribution dist) { public void testHelpDoesNotStartReAugJvm(KeycloakDistribution dist) {
for (String helpCmd : List.of("-h", "--help", "--help-all")) { for (String helpCmd : List.of("-h", "--help", "--help-all")) {
for (String cmd : List.of("", "start", "start-dev", "build")) { for (String cmd : List.of("", "start", "start-dev", "build")) {
CLIResult run = dist.run("--debug", cmd, helpCmd); String debugOption = "--debug";
if (OS.WINDOWS.isCurrentOs()) {
debugOption = "--debug=8787";
}
CLIResult run = dist.run(debugOption, cmd, helpCmd);
assertSingleJvmStarted(run); assertSingleJvmStarted(run);
} }
} }

View file

@ -20,6 +20,8 @@ package org.keycloak.it.cli.dist;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;
import org.keycloak.it.junit5.extension.BeforeStartDistribution; import org.keycloak.it.junit5.extension.BeforeStartDistribution;
import org.keycloak.it.junit5.extension.CLIResult; import org.keycloak.it.junit5.extension.CLIResult;
import org.keycloak.it.junit5.extension.DistributionTest; import org.keycloak.it.junit5.extension.DistributionTest;
@ -60,6 +62,7 @@ public class ImportAtStartupDistTest {
} }
@Test @Test
@EnabledOnOs(value = { OS.LINUX, OS.MAC }, disabledReason = "different shell escaping behaviour on Windows.")
@BeforeStartDistribution(CreateRealmConfigurationFile.class) @BeforeStartDistribution(CreateRealmConfigurationFile.class)
@Launch({"start-dev", "--import-realm=some-file"}) @Launch({"start-dev", "--import-realm=some-file"})
void failSetValueToImportRealmOption(LaunchResult result) { void failSetValueToImportRealmOption(LaunchResult result) {

View file

@ -65,4 +65,11 @@ public class StartCommandDistTest extends StartCommandTest {
cliResult.assertStarted(); cliResult.assertStarted();
} }
@Test
@Launch({ "start", "--optimized", "--http-enabled=true", "--hostname-strict=false", "--cache=local" })
void testStartUsingOptimizedDoesNotAllowBuildOptions(LaunchResult result) {
CLIResult cliResult = (CLIResult) result;
cliResult.assertError("Unknown option: '--cache'");
}
} }

View file

@ -93,4 +93,3 @@ Examples:
Change the relative path: Change the relative path:
$ kc.bat build --http-relative-path=/auth $ kc.bat build --http-relative-path=/auth