private CommandFactoryImpl newFactory(Properties userProps, System2 system2) { Properties p = new Properties(); p.setProperty("sonar.path.home", homeDir.getAbsolutePath()); p.setProperty("sonar.path.temp", tempDir.getAbsolutePath()); p.setProperty("sonar.path.logs", logsDir.getAbsolutePath()); p.putAll(userProps); Props props = new Props(p); ProcessProperties.completeDefaults(props); return new CommandFactoryImpl(props, tempDir, system2); }
@Override public AbstractCommand<?> createEsCommand() { if (system2.isOsWindows()) { return createEsCommandForWindows(); } return createEsCommandForUnix(); }
private EsScriptCommand createEsCommandForUnix() { EsInstallation esInstallation = createEsInstallation(); return new EsScriptCommand(ProcessId.ELASTICSEARCH, esInstallation.getHomeDirectory()) .setEsInstallation(esInstallation) .addOption("-Epath.conf=" + esInstallation.getConfDirectory().getAbsolutePath()) .setEnvVariable("ES_JVM_OPTIONS", esInstallation.getJvmOptions().getAbsolutePath()) .setEnvVariable("JAVA_HOME", System.getProperties().getProperty("java.home")) .suppressEnvVariable(ENV_VAR_JAVA_TOOL_OPTIONS) .suppressEnvVariable(ENV_VAR_ES_JAVA_OPTS); }
private <T extends JvmOptions> void addProxyJvmOptions(JvmOptions<T> jvmOptions) { for (String key : PROXY_PROPERTY_KEYS) { getPropsValue(key).ifPresent(val -> jvmOptions.add("-D" + key + "=" + val)); } // defaults of HTTPS are the same than HTTP defaults setSystemPropertyToDefaultIfNotSet(jvmOptions, HTTPS_PROXY_HOST.getKey(), HTTP_PROXY_HOST.getKey()); setSystemPropertyToDefaultIfNotSet(jvmOptions, HTTPS_PROXY_PORT.getKey(), HTTP_PROXY_PORT.getKey()); }
@Override public JavaCommand createWebCommand(boolean leader) { File homeDir = props.nonNullValueAsFile(PATH_HOME.getKey()); WebJvmOptions jvmOptions = new WebJvmOptions(tempDir) .addFromMandatoryProperty(props, WEB_JAVA_OPTS.getKey()) .addFromMandatoryProperty(props, WEB_JAVA_ADDITIONAL_OPTS.getKey()); addProxyJvmOptions(jvmOptions); JavaCommand<WebJvmOptions> command = new JavaCommand<WebJvmOptions>(ProcessId.WEB_SERVER, homeDir) .setReadsArgumentsFromFile(true) .setArguments(props.rawProperties()) .setJvmOptions(jvmOptions) // required for logback tomcat valve .setEnvVariable(PATH_LOGS.getKey(), props.nonNullValue(PATH_LOGS.getKey())) .setArgument("sonar.cluster.web.startupLeader", Boolean.toString(leader)) .setClassName("org.sonar.server.app.WebServer") .addClasspath("./lib/common/*"); String driverPath = props.value(JDBC_DRIVER_PATH.getKey()); if (driverPath != null) { command.addClasspath(driverPath); } command.suppressEnvVariable(ENV_VAR_JAVA_TOOL_OPTIONS); return command; }
private void setSystemPropertyToDefaultIfNotSet(JvmOptions jvmOptions, String httpsProperty, String httpProperty) { Optional<String> httpValue = getPropsValue(httpProperty); Optional<String> httpsValue = getPropsValue(httpsProperty); if (!httpsValue.isPresent() && httpValue.isPresent()) { jvmOptions.add("-D" + httpsProperty + "=" + httpValue.get()); } }
@Test public void createEsCommand_throws_ISE_if_es_binary_is_not_found() { expectedException.expect(IllegalStateException.class); expectedException.expectMessage("Cannot find elasticsearch binary"); newFactory(new Properties()).createEsCommand(); }
@Test public void createWebCommand_adds_configured_jdbc_driver_to_classpath() throws Exception { Properties props = new Properties(); File driverFile = temp.newFile(); props.setProperty("sonar.jdbc.driverPath", driverFile.getAbsolutePath()); JavaCommand command = newFactory(props).createWebCommand(true); assertThat(command.getClasspath()) .containsExactlyInAnyOrder("./lib/common/*", driverFile.getAbsolutePath()); }
@Test public void createCeCommand_returns_command_for_default_settings() { JavaCommand command = newFactory(new Properties()).createCeCommand(); assertThat(command.getClassName()).isEqualTo("org.sonar.ce.app.CeServer"); assertThat(command.getWorkDir().getAbsolutePath()).isEqualTo(homeDir.getAbsolutePath()); assertThat(command.getClasspath()) .containsExactly("./lib/common/*"); assertThat(command.getJvmOptions().getAll()) // enforced values .contains("-Djava.awt.headless=true", "-Dfile.encoding=UTF-8") // default settings .contains("-Djava.io.tmpdir=" + tempDir.getAbsolutePath(), "-Dfile.encoding=UTF-8") .contains("-Xmx512m", "-Xms128m", "-XX:+HeapDumpOnOutOfMemoryError"); assertThat(command.getProcessId()).isEqualTo(ProcessId.COMPUTE_ENGINE); assertThat(command.getEnvVariables()) .isNotEmpty(); assertThat(command.getArguments()) // default settings .contains(entry("sonar.web.javaOpts", "-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError")) .contains(entry("sonar.cluster.enabled", "false")); assertThat(command.getSuppressedEnvVariables()).containsOnly("JAVA_TOOL_OPTIONS"); }
private <T extends JvmOptions> void addProxyJvmOptions(JvmOptions<T> jvmOptions) { for (String key : PROXY_PROPERTY_KEYS) { getPropsValue(key).ifPresent(val -> jvmOptions.add("-D" + key + "=" + val)); } // defaults of HTTPS are the same than HTTP defaults setSystemPropertyToDefaultIfNotSet(jvmOptions, HTTPS_PROXY_HOST, HTTP_PROXY_HOST); setSystemPropertyToDefaultIfNotSet(jvmOptions, HTTPS_PROXY_PORT, HTTP_PROXY_PORT); }
@Override public JavaCommand createCeCommand() { File homeDir = props.nonNullValueAsFile(PATH_HOME.getKey()); CeJvmOptions jvmOptions = new CeJvmOptions(tempDir) .addFromMandatoryProperty(props, CE_JAVA_OPTS.getKey()) .addFromMandatoryProperty(props, CE_JAVA_ADDITIONAL_OPTS.getKey()); addProxyJvmOptions(jvmOptions); JavaCommand<CeJvmOptions> command = new JavaCommand<CeJvmOptions>(ProcessId.COMPUTE_ENGINE, homeDir) .setReadsArgumentsFromFile(true) .setArguments(props.rawProperties()) .setJvmOptions(jvmOptions) .setClassName("org.sonar.ce.app.CeServer") .addClasspath("./lib/common/*"); String driverPath = props.value(JDBC_DRIVER_PATH.getKey()); if (driverPath != null) { command.addClasspath(driverPath); } command.suppressEnvVariable(ENV_VAR_JAVA_TOOL_OPTIONS); return command; }
private void setSystemPropertyToDefaultIfNotSet(JvmOptions jvmOptions, String httpsProperty, String httpProperty) { Optional<String> httpValue = getPropsValue(httpProperty); Optional<String> httpsValue = getPropsValue(httpsProperty); if (!httpsValue.isPresent() && httpValue.isPresent()) { jvmOptions.add("-D" + httpsProperty + "=" + httpValue.get()); } }
@Test public void createEsCommand_returns_command_for_overridden_settings() throws Exception { prepareEsFileSystem(); Properties props = new Properties(); props.setProperty("sonar.search.host", "localhost"); props.setProperty("sonar.cluster.name", "foo"); props.setProperty("sonar.search.port", "1234"); props.setProperty("sonar.search.javaOpts", "-Xms10G -Xmx10G"); AbstractCommand esCommand = newFactory(props).createEsCommand(); EsInstallation esConfig = esCommand.getEsInstallation(); assertThat(esConfig.getClusterName()).isEqualTo("foo"); assertThat(esConfig.getPort()).isEqualTo(1234); assertThat(esConfig.getEsJvmOptions().getAll()) // enforced values .contains("-XX:+UseConcMarkSweepGC", "-server", "-Dfile.encoding=UTF-8") // user settings .contains("-Xms10G", "-Xmx10G") // default values disabled .doesNotContain("-XX:+HeapDumpOnOutOfMemoryError"); }
@Test public void createWebCommand_returns_command_for_default_settings() { JavaCommand command = newFactory(new Properties()).createWebCommand(true); assertThat(command.getClassName()).isEqualTo("org.sonar.server.app.WebServer"); assertThat(command.getWorkDir().getAbsolutePath()).isEqualTo(homeDir.getAbsolutePath()); assertThat(command.getClasspath()) .containsExactly("./lib/common/*"); assertThat(command.getJvmOptions().getAll()) // enforced values .contains("-Djava.awt.headless=true", "-Dfile.encoding=UTF-8") // default settings .contains("-Djava.io.tmpdir=" + tempDir.getAbsolutePath(), "-Dfile.encoding=UTF-8") .contains("-Xmx512m", "-Xms128m", "-XX:+HeapDumpOnOutOfMemoryError"); assertThat(command.getProcessId()).isEqualTo(ProcessId.WEB_SERVER); assertThat(command.getEnvVariables()) .isNotEmpty(); assertThat(command.getArguments()) // default settings .contains(entry("sonar.web.javaOpts", "-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError")) .contains(entry("sonar.cluster.enabled", "false")); assertThat(command.getSuppressedEnvVariables()).containsOnly("JAVA_TOOL_OPTIONS"); }
@Override public AbstractCommand<?> createEsCommand() { if (system2.isOsWindows()) { return createEsCommandForWindows(); } return createEsCommandForUnix(); }
@Test public void constructor_logs_no_warning_if_env_variable_JAVA_TOOL_OPTIONS_is_not_set() { System2 system2 = Mockito.mock(System2.class); when(system2.getenv(anyString())).thenReturn(null); attachMemoryAppenderToLoggerOf(CommandFactoryImpl.class); new CommandFactoryImpl(new Props(new Properties()), tempDir, system2); assertThat(listAppender.getLogs()).isEmpty(); }
private JavaCommand createEsCommandForWindows() { EsInstallation esInstallation = createEsInstallation(); return new JavaCommand<EsJvmOptions>(ProcessId.ELASTICSEARCH, esInstallation.getHomeDirectory()) .setEsInstallation(esInstallation) .setReadsArgumentsFromFile(false) .setArgument("path.conf", esInstallation.getConfDirectory().getAbsolutePath()) .setJvmOptions(new EsJvmOptions() .addFromMandatoryProperty(props, SEARCH_JAVA_OPTS.getKey()) .addFromMandatoryProperty(props, SEARCH_JAVA_ADDITIONAL_OPTS.getKey()) .add("-Delasticsearch") .add("-Des.path.home=" + esInstallation.getHomeDirectory())) .setEnvVariable("ES_JVM_OPTIONS", esInstallation.getJvmOptions().getAbsolutePath()) .setEnvVariable("JAVA_HOME", System.getProperties().getProperty("java.home")) .setClassName("org.elasticsearch.bootstrap.Elasticsearch") .addClasspath("lib/*") .suppressEnvVariable(ENV_VAR_JAVA_TOOL_OPTIONS) .suppressEnvVariable(ENV_VAR_ES_JAVA_OPTS); }
@Override public JavaCommand createWebCommand(boolean leader) { File homeDir = props.nonNullValueAsFile(ProcessProperties.PATH_HOME); WebJvmOptions jvmOptions = new WebJvmOptions(tempDir) .addFromMandatoryProperty(props, ProcessProperties.WEB_JAVA_OPTS) .addFromMandatoryProperty(props, ProcessProperties.WEB_JAVA_ADDITIONAL_OPTS); addProxyJvmOptions(jvmOptions); JavaCommand<WebJvmOptions> command = new JavaCommand<WebJvmOptions>(ProcessId.WEB_SERVER, homeDir) .setReadsArgumentsFromFile(true) .setArguments(props.rawProperties()) .setJvmOptions(jvmOptions) // required for logback tomcat valve .setEnvVariable(ProcessProperties.PATH_LOGS, props.nonNullValue(ProcessProperties.PATH_LOGS)) .setArgument("sonar.cluster.web.startupLeader", Boolean.toString(leader)) .setClassName("org.sonar.server.app.WebServer") .addClasspath("./lib/common/*") .addClasspath("./lib/server/*"); String driverPath = props.value(ProcessProperties.JDBC_DRIVER_PATH); if (driverPath != null) { command.addClasspath(driverPath); } command.suppressEnvVariable(ENV_VAR_JAVA_TOOL_OPTIONS); return command; }
@Test public void createEsCommand_for_unix_returns_command_for_default_settings() throws Exception { System2 system2 = Mockito.mock(System2.class); when(system2.isOsWindows()).thenReturn(false); prepareEsFileSystem(); Properties props = new Properties(); props.setProperty("sonar.search.host", "localhost"); AbstractCommand esCommand = newFactory(props, system2).createEsCommand(); EsInstallation esConfig = esCommand.getEsInstallation(); assertThat(esCommand).isInstanceOf(EsScriptCommand.class); assertThat(esConfig.getClusterName()).isEqualTo("sonarqube"); assertThat(esConfig.getHost()).isNotEmpty(); assertThat(esConfig.getPort()).isEqualTo(9001); assertThat(esConfig.getEsJvmOptions().getAll()) // enforced values .contains("-XX:+UseConcMarkSweepGC", "-server", "-Dfile.encoding=UTF-8") // default settings .contains("-Xms512m", "-Xmx512m", "-XX:+HeapDumpOnOutOfMemoryError"); File esConfDir = new File(tempDir, "conf/es"); assertThat(esCommand.getEnvVariables()) .contains(entry("ES_JVM_OPTIONS", new File(esConfDir, "jvm.options").getAbsolutePath())) .containsKey("JAVA_HOME"); assertThat(esConfig.getEsYmlSettings()).isNotNull(); assertThat(esConfig.getLog4j2Properties()) .contains(entry("appender.file_es.fileName", new File(logsDir, "es.log").getAbsolutePath())); assertThat(esCommand.getSuppressedEnvVariables()).containsOnly("JAVA_TOOL_OPTIONS", "ES_JAVA_OPTS"); }
@Test public void createWebCommand_configures_command_with_overridden_settings() { Properties props = new Properties(); props.setProperty("sonar.web.port", "1234"); props.setProperty("sonar.web.javaOpts", "-Xmx10G"); JavaCommand command = newFactory(props).createWebCommand(true); assertThat(command.getJvmOptions().getAll()) // enforced values .contains("-Djava.awt.headless=true", "-Dfile.encoding=UTF-8") // default settings .contains("-Djava.io.tmpdir=" + tempDir.getAbsolutePath(), "-Dfile.encoding=UTF-8") // overridden values .contains("-Xmx10G") .doesNotContain("-Xms128m", "-XX:+HeapDumpOnOutOfMemoryError"); assertThat(command.getArguments()) // default settings .contains(entry("sonar.web.javaOpts", "-Xmx10G")) .contains(entry("sonar.cluster.enabled", "false")); assertThat(command.getSuppressedEnvVariables()).containsOnly("JAVA_TOOL_OPTIONS"); }