Merge changes from topic 'win32'

* changes:
  New daemon start/stop methods for use with Procrun
  Correctly call ssh-keygen on Win32 with empty passphrase
  Redirect output from ssh-keygen call to console to see potential errors
This commit is contained in:
David Pursehouse
2016-09-23 12:12:11 +00:00
committed by Gerrit Code Review
5 changed files with 124 additions and 17 deletions

View File

@@ -172,6 +172,50 @@ To install Gerrit into an existing servlet container instead of using
the embedded Jetty server, see
link:install-j2ee.html[J2EE installation].
[[installation_on_windows]]
== Installation on Windows
If new site is going to be initialized with Bouncy Castle cryptography,
ssh-keygen command must be available during the init phase. If you have
link:https://git-for-windows.github.io/[Git for Windows] installed,
start Command Prompt and temporary add directory with ssh-keygen to the
PATH environment variable just before running init command:
====
PATH=%PATH%;c:\Program Files\Git\usr\bin
====
Please note that the path in the above example must not be
double-quoted.
To run the daemon after site initialization execute:
====
cd C:\MY\GERRIT\SITE
java.exe -jar bin\gerrit.war daemon --console-log
====
To stop the daemon press Ctrl+C.
=== Install the daemon as Windows Service
To install Gerrit as Windows Service use the
link:http://commons.apache.org/proper/commons-daemon/procrun.html[Apache
Commons Daemon Procrun].
Sample install command:
====
prunsrv.exe //IS//Gerrit --DisplayName="Gerrit Code Review" --Startup=auto ^
--Jvm="C:\Program Files\Java\jre1.8.0_65\bin\server\jvm.dll" ^
--Classpath=C:\MY\GERRIT\SITE\bin\gerrit.war ^
--LogPath=C:\MY\GERRIT\SITE\logs ^
--StartPath=C:\MY\GERRIT\SITE ^
--StartMode=jvm --StopMode=jvm ^
--StartClass=com.google.gerrit.launcher.GerritLauncher --StartMethod=daemonStart ^
--StopClass=com.google.gerrit.launcher.GerritLauncher --StopMethod=daemonStop ^
++DependsOn=postgresql-x64-9.4
====
[[customize]]
== Site Customization

View File

@@ -55,6 +55,8 @@ public final class GerritLauncher {
private static final String pkg = "com.google.gerrit.pgm";
public static final String NOT_ARCHIVED = "NOT_ARCHIVED";
private static ClassLoader daemonClassLoader;
public static void main(final String[] argv) throws Exception {
System.exit(mainImpl(argv));
}
@@ -102,6 +104,44 @@ public final class GerritLauncher {
return invokeProgram(cl, argv);
}
public static void daemonStart(final String[] argv) throws Exception {
if (daemonClassLoader != null) {
throw new IllegalStateException(
"daemonStart can be called only once per JVM instance");
}
final ClassLoader cl = libClassLoader(false);
Thread.currentThread().setContextClassLoader(cl);
daemonClassLoader = cl;
String[] daemonArgv = new String[argv.length + 1];
daemonArgv[0] = "daemon";
for (int i = 0; i < argv.length; i++) {
daemonArgv[i + 1] = argv[i];
}
int res = invokeProgram(cl, daemonArgv);
if (res != 0) {
throw new Exception("Unexpected return value: " + res);
}
}
public static void daemonStop(final String[] argv) throws Exception {
if (daemonClassLoader == null) {
throw new IllegalStateException(
"daemonStop can be called only after call to daemonStop");
}
String[] daemonArgv = new String[argv.length + 2];
daemonArgv[0] = "daemon";
daemonArgv[1] = "--stop-only";
for (int i = 0; i < argv.length; i++) {
daemonArgv[i + 2] = argv[i];
}
int res = invokeProgram(daemonClassLoader, daemonArgv);
if (res != 0) {
throw new Exception("Unexpected return value: " + res);
}
}
private static boolean isProlog(String cn) {
return "PrologShell".equals(cn) || "Rulec".equals(cn);
}

View File

@@ -125,7 +125,7 @@ public class Daemon extends SiteProgram {
private boolean sshd = true;
@Option(name = "--disable-sshd", usage = "Disable the internal SSH daemon")
void setDisableSshd(@SuppressWarnings("unused") boolean arg) {
void setDisableSshd(@SuppressWarnings("unused") boolean arg) {
sshd = false;
}
@@ -151,6 +151,9 @@ public class Daemon extends SiteProgram {
usage = "Init site before starting the daemon")
private boolean doInit;
@Option(name = "--stop-only", usage = "Stop the daemon", hidden = true)
private boolean stopOnly;
private final LifecycleManager manager = new LifecycleManager();
private Injector dbInjector;
private Injector cfgInjector;
@@ -181,6 +184,10 @@ public class Daemon extends SiteProgram {
@Override
public int run() throws Exception {
if (stopOnly) {
RuntimeShutdown.manualShutdown();
return 0;
}
if (doInit) {
try {
new Init(getSitePath()).run();
@@ -214,14 +221,7 @@ public class Daemon extends SiteProgram {
@Override
public void run() {
log.info("caught shutdown, cleaning up");
if (runId != null) {
try {
Files.delete(runFile);
} catch (IOException err) {
log.warn("failed to delete " + runFile, err);
}
}
manager.stop();
stop();
}
});
@@ -313,6 +313,13 @@ public class Daemon extends SiteProgram {
@VisibleForTesting
public void stop() {
if (runId != null) {
try {
Files.delete(runFile);
} catch (IOException err) {
log.warn("failed to delete " + runFile, err);
}
}
manager.stop();
}

View File

@@ -23,6 +23,7 @@ import com.google.gerrit.pgm.init.api.ConsoleUI;
import com.google.gerrit.pgm.init.api.InitStep;
import com.google.gerrit.pgm.init.api.Section;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.util.HostPlatform;
import com.google.gerrit.server.util.SocketUtil;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -31,6 +32,7 @@ import org.apache.sshd.common.util.SecurityUtils;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -103,25 +105,30 @@ class InitSshd implements InitStep {
//
final String comment = "gerrit-code-review@" + hostname();
// Workaround for JDK-6518827 - zero-length argument ignored on Win32
String emptyPassphraseArg = HostPlatform.isWin32() ? "\"\"" : "";
System.err.print(" rsa...");
System.err.flush();
Runtime.getRuntime().exec(new String[] {"ssh-keygen",
new ProcessBuilder("ssh-keygen",
"-q" /* quiet */,
"-t", "rsa",
"-P", "",
"-P", emptyPassphraseArg,
"-C", comment,
"-f", site.ssh_rsa.toAbsolutePath().toString(),
}).waitFor();
"-f", site.ssh_rsa.toAbsolutePath().toString()
).redirectError(Redirect.INHERIT).redirectOutput(Redirect.INHERIT)
.start().waitFor();
System.err.print(" dsa...");
System.err.flush();
Runtime.getRuntime().exec(new String[] {"ssh-keygen",
new ProcessBuilder("ssh-keygen",
"-q" /* quiet */,
"-t", "dsa",
"-P", "",
"-P", emptyPassphraseArg,
"-C", comment,
"-f", site.ssh_dsa.toAbsolutePath().toString(),
}).waitFor();
"-f", site.ssh_dsa.toAbsolutePath().toString()
).redirectError(Redirect.INHERIT).redirectOutput(Redirect.INHERIT)
.start().waitFor();
} else {
// Generate the SSH daemon host key ourselves. This is complex

View File

@@ -39,6 +39,10 @@ public class RuntimeShutdown {
cb.waitForShutdown();
}
public static void manualShutdown() {
cb.manualShutdown();
}
private RuntimeShutdown() {
}
@@ -96,6 +100,11 @@ public class RuntimeShutdown {
}
}
void manualShutdown() {
Runtime.getRuntime().removeShutdownHook(this);
run();
}
void waitForShutdown() {
synchronized (this) {
while (!shutdownComplete) {