import java.io.File;
import java.util.Map;
import java.util.Optional;
+import org.slf4j.LoggerFactory;
import org.sonar.process.ProcessId;
import org.sonar.process.ProcessProperties;
import org.sonar.process.Props;
+import org.sonar.process.System2;
import org.sonar.process.es.EsFileSystem;
import org.sonar.process.es.EsLogging;
import org.sonar.process.es.EsSettings;
import static org.sonar.process.ProcessProperties.HTTP_PROXY_PORT;
public class CommandFactoryImpl implements CommandFactory {
+ private static final String ENV_VAR_JAVA_TOOL_OPTIONS = "JAVA_TOOL_OPTIONS";
/**
* Properties about proxy that must be set as system properties
*/
private final Props props;
private final File tempDir;
- public CommandFactoryImpl(Props props, File tempDir) {
+ public CommandFactoryImpl(Props props, File tempDir, System2 system2) {
this.props = props;
this.tempDir = tempDir;
+ String javaToolOptions = system2.getenv(ENV_VAR_JAVA_TOOL_OPTIONS);
+ if (javaToolOptions != null && !javaToolOptions.trim().isEmpty()) {
+ LoggerFactory.getLogger(CommandFactoryImpl.class)
+ .warn("JAVA_TOOL_OPTIONS is defined but will be ignored. " +
+ "Use properties sonar.*.javaOpts and/or sonar.*.javaAdditionalOpts in sonar.properties to change SQ JVM processes options");
+ }
}
@Override
.setClusterName(settingsMap.get("cluster.name"))
.setHost(settingsMap.get("network.host"))
.setPort(Integer.valueOf(settingsMap.get("transport.tcp.port")))
- .addEsOption("-Epath.conf="+esFileSystem.getConfDirectory().getAbsolutePath())
+ .addEsOption("-Epath.conf=" + esFileSystem.getConfDirectory().getAbsolutePath())
.setEsJvmOptions(new EsJvmOptions()
.addFromMandatoryProperty(props, ProcessProperties.SEARCH_JAVA_OPTS)
.addFromMandatoryProperty(props, ProcessProperties.SEARCH_JAVA_ADDITIONAL_OPTS))
.setEsYmlSettings(new EsYmlSettings(settingsMap))
.setEnvVariable("ES_JVM_OPTIONS", esFileSystem.getJvmOptions().getAbsolutePath())
- .setEnvVariable("JAVA_HOME", System.getProperties().getProperty("java.home"));
+ .setEnvVariable("JAVA_HOME", System.getProperties().getProperty("java.home"))
+ .suppressEnvVariable(ENV_VAR_JAVA_TOOL_OPTIONS);
}
@Override
if (driverPath != null) {
command.addClasspath(driverPath);
}
+ command.suppressEnvVariable(ENV_VAR_JAVA_TOOL_OPTIONS);
return command;
}
if (driverPath != null) {
command.addClasspath(driverPath);
}
+ command.suppressEnvVariable(ENV_VAR_JAVA_TOOL_OPTIONS);
return command;
}
*/
package org.sonar.process.command;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.AppenderBase;
import java.io.File;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Properties;
import org.apache.commons.io.FileUtils;
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
+import org.mockito.Mockito;
import org.sonar.process.ProcessId;
import org.sonar.process.ProcessProperties;
import org.sonar.process.Props;
+import org.sonar.process.System2;
+import org.sonar.process.logging.LogbackHelper;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
public class CommandFactoryImplTest {
+
+ private static final String MEMORY_APPENDER_NAME = "MEMORY_APPENDER";
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Rule
private File homeDir;
private File tempDir;
private File logsDir;
+ private ListAppender listAppender;
@Before
public void setUp() throws Exception {
logsDir = temp.newFolder();
}
+ @After
+ public void tearDown() throws Exception {
+ if (listAppender != null) {
+ listAppender.stop();
+ new LogbackHelper().getRootContext().getLogger(CommandFactoryImpl.class)
+ .detachAppender(listAppender);
+ }
+ }
+
+ @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();
+ }
+
+ @Test
+ public void constructor_logs_warning_if_env_variable_JAVA_TOOL_OPTIONS_is_set() {
+ System2 system2 = Mockito.mock(System2.class);
+ when(system2.getenv("JAVA_TOOL_OPTIONS")).thenReturn("sds");
+ attachMemoryAppenderToLoggerOf(CommandFactoryImpl.class);
+
+ new CommandFactoryImpl(new Props(new Properties()), tempDir, system2);
+
+ assertThat(listAppender.getLogs())
+ .extracting(ILoggingEvent::getMessage)
+ .containsOnly(
+ "JAVA_TOOL_OPTIONS is defined but will be ignored. " +
+ "Use properties sonar.*.javaOpts and/or sonar.*.javaAdditionalOpts in sonar.properties to change SQ JVM processes options");
+ }
+
@Test
public void createEsCommand_throws_ISE_if_es_binary_is_not_found() throws Exception {
expectedException.expect(IllegalStateException.class);
assertThat(esCommand.getLog4j2Properties())
.contains(entry("appender.file_es.fileName", new File(logsDir, "es.log").getAbsolutePath()));
+
+ assertThat(esCommand.getSuppressedEnvVariables()).containsOnly("JAVA_TOOL_OPTIONS");
}
@Test
// default settings
.contains(entry("sonar.web.javaOpts", "-Xmx512m -Xms128m -XX:+HeapDumpOnOutOfMemoryError"))
.contains(entry("sonar.cluster.enabled", "false"));
+
+ assertThat(command.getSuppressedEnvVariables()).containsOnly("JAVA_TOOL_OPTIONS");
}
@Test
// default settings
.contains(entry("sonar.web.javaOpts", "-Xmx10G"))
.contains(entry("sonar.cluster.enabled", "false"));
+
+ assertThat(command.getSuppressedEnvVariables()).containsOnly("JAVA_TOOL_OPTIONS");
}
@Test
Props props = new Props(p);
ProcessProperties.completeDefaults(props);
- return new CommandFactoryImpl(props, tempDir);
+ return new CommandFactoryImpl(props, tempDir, System2.INSTANCE);
+ }
+
+ private <T> void attachMemoryAppenderToLoggerOf(Class<T> loggerClass) {
+ this.listAppender = new ListAppender();
+ new LogbackHelper().getRootContext().getLogger(loggerClass)
+ .addAppender(listAppender);
+ listAppender.start();
+ }
+
+ private static final class ListAppender extends AppenderBase<ILoggingEvent> {
+ private final List<ILoggingEvent> logs = new ArrayList<>();
+
+ @Override
+ public String getName() {
+ return MEMORY_APPENDER_NAME;
+ }
+
+ @Override
+ protected void append(ILoggingEvent eventObject) {
+ logs.add(eventObject);
+ }
+
+ public List<ILoggingEvent> getLogs() {
+ return logs;
+ }
}
}
import org.sonar.application.process.ProcessLauncherImpl;
import org.sonar.application.process.StopRequestWatcher;
import org.sonar.application.process.StopRequestWatcherImpl;
+import org.sonar.process.System2;
import org.sonar.process.SystemExit;
import org.sonar.process.command.CommandFactory;
import org.sonar.process.command.CommandFactoryImpl;
appState.registerClusterName(settings.getProps().value(CLUSTER_NAME, "sonarqube"));
AppReloader appReloader = new AppReloaderImpl(settingsLoader, fileSystem, appState, logging);
fileSystem.reset();
- CommandFactory commandFactory = new CommandFactoryImpl(settings.getProps(), fileSystem.getTempDir());
+ CommandFactory commandFactory = new CommandFactoryImpl(settings.getProps(), fileSystem.getTempDir(), System2.INSTANCE);
try (ProcessLauncher processLauncher = new ProcessLauncherImpl(fileSystem.getTempDir())) {
Scheduler scheduler = new SchedulerImpl(settings, appReloader, commandFactory, processLauncher, appState);