From 6bc55b17ebd87802cb9b55d5b6625e1a935f3909 Mon Sep 17 00:00:00 2001
From: Simon Brandhof
Date: Wed, 16 Mar 2016 23:01:11 +0100
Subject: [PATCH] SONAR-7436 Monitoring of CE process in system WS and console
---
.../it/serverSystem/ServerSystemTest.java | 19 +++
.../sonar/ce/app/WebServerWatcherImpl.java | 4 +-
.../container/ComputeEngineContainerImpl.java | 4 +-
.../ce/app/WebServerWatcherImplTest.java | 4 +-
.../ComputeEngineContainerImplTest.java | 6 +-
.../sonar/process/monitor/JavaCommand.java | 24 +--
.../process/monitor/JavaProcessLauncher.java | 40 +++--
.../process/monitor/JavaCommandTest.java | 6 +-
.../monitor/JavaProcessLauncherTest.java | 5 +-
.../sonar/process/monitor/MonitorTest.java | 65 +++++----
server/sonar-process/pom.xml | 14 +-
.../sonar/process/AllProcessesCommands.java | 52 ++++++-
.../sonar/process/DefaultProcessCommands.java | 10 ++
.../org/sonar/process/ProcessCommands.java | 6 +-
.../org/sonar/process/ProcessEntryPoint.java | 12 ++
.../java/org/sonar/process/ProcessId.java | 53 +++++++
.../sonar/process/jmx/CeDatabaseMBean.java | 43 ++++++
.../org/sonar/process/jmx/CeTasksMBean.java} | 11 +-
.../sonar/process/jmx/EsSettingsMBean.java | 38 +++++
.../main/java/org/sonar/process/jmx/Jmx.java | 86 +++++++++++
.../org/sonar/process/jmx/JmxConnection.java | 97 ++++++++++++
.../process/jmx/JmxConnectionFactory.java | 57 ++++++++
.../org/sonar/process/jmx/package-info.java | 23 +++
.../process/AllProcessesCommandsTest.java | 14 ++
.../sonar/process/ProcessEntryPointTest.java | 12 +-
.../java/org/sonar/process/ProcessIdTest.java | 47 ++++++
.../test/java/org/sonar/process/jmx/Fake.java | 27 ++++
.../java/org/sonar/process/jmx/FakeMBean.java | 24 +++
.../sonar/process/jmx/JmxConnectionTest.java | 36 +++++
.../java/org/sonar/process/jmx/JmxTest.java | 87 +++++++++++
.../java/org/sonar/process/jmx/test/Fake.java | 30 ++++
.../{SearchSettings.java => EsSettings.java} | 35 +++--
.../java/org/sonar/search/SearchServer.java | 8 +-
...hSettingsTest.java => EsSettingsTest.java} | 30 ++--
.../org/sonar/search/SearchServerTest.java | 7 +-
.../src/main/java/org/sonar/ce/CeModule.java | 4 -
.../sonar/ce/monitoring/CEQueueStatus.java | 52 +------
.../ce/monitoring/DummyCEQueueStatusImpl.java | 93 ------------
.../java/org/sonar/ce/queue/CeQueueImpl.java | 11 +-
.../server/app/ProcessCommandWrapper.java | 1 +
.../server/app/ProcessCommandWrapperImpl.java | 24 +--
.../sonar/server/computation/CeModule.java | 2 +
.../monitoring/CEQueueStatusImpl.java | 65 ++-------
.../monitoring/CeDatabaseMBeanImpl.java | 97 ++++++++++++
...ueueMonitor.java => CeTasksMBeanImpl.java} | 39 ++---
.../computation/queue/CeQueueInitializer.java | 10 +-
.../computation/queue/CeQueueModule.java | 6 +-
.../queue/InternalCeQueueImpl.java | 12 +-
.../platform/monitoring/BaseMonitorMBean.java | 29 +---
.../monitoring/CeDatabaseMonitor.java | 58 ++++++++
.../platform/monitoring/CeStateMonitor.java | 46 ++++++
.../platform/monitoring/CeTasksMonitor.java | 55 +++++++
.../platform/monitoring/DatabaseMonitor.java | 13 +-
.../server/platform/monitoring/EsMonitor.java | 25 +++-
.../platform/monitoring/EsStateMonitor.java | 46 ++++++
.../monitoring/JmxConnectorProvider.java | 46 ++++++
...rtiesMonitor.java => JvmPropsMonitor.java} | 3 +-
.../platformlevel/PlatformLevel4.java | 14 +-
.../CEQueueStatusImplConcurrentTest.java | 19 +--
.../org/sonar/ce/queue/CeQueueImplTest.java | 41 +-----
.../app/ProcessCommandWrapperImplTest.java | 12 +-
.../monitoring/CEQueueStatusImplTest.java | 138 +++---------------
...torTest.java => CeTasksMBeanImplTest.java} | 64 +++-----
.../queue/CeQueueInitializerTest.java | 56 +------
.../queue/InternalCeQueueImplTest.java | 32 +---
.../org/sonar/server/es/EsServerHolder.java | 7 +-
.../monitoring/BaseMonitorMBeanTest.java | 8 +-
.../monitoring/CeDatabaseMonitorTest.java | 53 +++++++
.../monitoring/CeStateMonitorTest.java | 53 +++++++
.../monitoring/CeTasksMonitorTest.java | 53 +++++++
.../monitoring/DatabaseMonitorTest.java | 5 +
.../platform/monitoring/EsMonitorTest.java | 39 +++--
.../monitoring/EsStateMonitorTest.java | 52 +++++++
.../JmxConnectionFactoryProviderTest.java | 56 +++++++
...itorTest.java => JvmPropsMonitorTest.java} | 13 +-
.../monitoring/SonarQubeMonitorTest.java | 5 +
.../sonar-web/src/main/js/apps/system/main.js | 4 +-
.../main/java/org/sonar/application/App.java | 16 +-
.../java/org/sonar/application/AppTest.java | 7 +-
79 files changed, 1757 insertions(+), 763 deletions(-)
create mode 100644 server/sonar-process/src/main/java/org/sonar/process/ProcessId.java
create mode 100644 server/sonar-process/src/main/java/org/sonar/process/jmx/CeDatabaseMBean.java
rename server/{sonar-server/src/main/java/org/sonar/server/computation/monitoring/ComputeEngineQueueMonitorMBean.java => sonar-process/src/main/java/org/sonar/process/jmx/CeTasksMBean.java} (85%)
create mode 100644 server/sonar-process/src/main/java/org/sonar/process/jmx/EsSettingsMBean.java
create mode 100644 server/sonar-process/src/main/java/org/sonar/process/jmx/Jmx.java
create mode 100644 server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnection.java
create mode 100644 server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnectionFactory.java
create mode 100644 server/sonar-process/src/main/java/org/sonar/process/jmx/package-info.java
create mode 100644 server/sonar-process/src/test/java/org/sonar/process/ProcessIdTest.java
create mode 100644 server/sonar-process/src/test/java/org/sonar/process/jmx/Fake.java
create mode 100644 server/sonar-process/src/test/java/org/sonar/process/jmx/FakeMBean.java
create mode 100644 server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionTest.java
create mode 100644 server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTest.java
create mode 100644 server/sonar-process/src/test/java/org/sonar/process/jmx/test/Fake.java
rename server/sonar-search/src/main/java/org/sonar/search/{SearchSettings.java => EsSettings.java} (88%)
rename server/sonar-search/src/test/java/org/sonar/search/{SearchSettingsTest.java => EsSettingsTest.java} (87%)
delete mode 100644 server/sonar-server/src/main/java/org/sonar/ce/monitoring/DummyCEQueueStatusImpl.java
create mode 100644 server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeDatabaseMBeanImpl.java
rename server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/{ComputeEngineQueueMonitor.java => CeTasksMBeanImpl.java} (59%)
create mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeDatabaseMonitor.java
create mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeStateMonitor.java
create mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeTasksMonitor.java
create mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStateMonitor.java
create mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JmxConnectorProvider.java
rename server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/{JvmPropertiesMonitor.java => JvmPropsMonitor.java} (96%)
rename server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/{ComputeEngineQueueMonitorTest.java => CeTasksMBeanImplTest.java} (70%)
create mode 100644 server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeDatabaseMonitorTest.java
create mode 100644 server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeStateMonitorTest.java
create mode 100644 server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeTasksMonitorTest.java
create mode 100644 server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/EsStateMonitorTest.java
create mode 100644 server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JmxConnectionFactoryProviderTest.java
rename server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/{JvmPropertiesMonitorTest.java => JvmPropsMonitorTest.java} (86%)
diff --git a/it/it-tests/src/test/java/it/serverSystem/ServerSystemTest.java b/it/it-tests/src/test/java/it/serverSystem/ServerSystemTest.java
index 64c72d3faec..51192aac4bc 100644
--- a/it/it-tests/src/test/java/it/serverSystem/ServerSystemTest.java
+++ b/it/it-tests/src/test/java/it/serverSystem/ServerSystemTest.java
@@ -40,12 +40,15 @@ import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.sonar.wsclient.services.Server;
import org.sonar.wsclient.services.ServerQuery;
+import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.WsResponse;
import util.ItUtils;
import util.QaOnly;
import util.selenium.SeleneseTest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
+import static util.ItUtils.newAdminWsClient;
@Category(QaOnly.class)
public class ServerSystemTest {
@@ -89,6 +92,22 @@ public class ServerSystemTest {
new SeleneseTest(selenese).runOn(orchestrator);
}
+ /**
+ * SONAR-7436
+ */
+ @Test
+ public void monitor_compute_engine_and_elasticsearch_processes() throws Exception {
+ WsResponse response = newAdminWsClient(orchestrator).wsConnector().call(
+ new GetRequest("api/system/info"));
+ assertThat(response.code()).isEqualTo(200);
+
+ assertThat(response.content()).containsSequence("\"Compute Engine Database\":", "\"Pool Active Connections\"");
+ assertThat(response.content()).containsSequence("\"Compute Engine State\":", "\"Heap Used\"");
+ assertThat(response.content()).containsSequence("\"Compute Engine Tasks\":", "\"Pending\"", "\"In Progress\"");
+
+ assertThat(response.content()).containsSequence("\"Elasticsearch\":", "\"State\":\"GREEN\"");
+ }
+
/**
* See http://jira.codehaus.org/browse/SONAR-2727
*/
diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/app/WebServerWatcherImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/app/WebServerWatcherImpl.java
index 4ebc8f80030..73bde24aa0e 100644
--- a/server/sonar-ce/src/main/java/org/sonar/ce/app/WebServerWatcherImpl.java
+++ b/server/sonar-ce/src/main/java/org/sonar/ce/app/WebServerWatcherImpl.java
@@ -23,10 +23,10 @@ import java.io.File;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.process.DefaultProcessCommands;
+import org.sonar.process.ProcessId;
public class WebServerWatcherImpl implements WebServerWatcher {
private static final Logger LOG = Loggers.get(WebServerWatcherImpl.class);
- private static final int WEB_SERVER_PROCESS_NUMBER = 2;
private static final int POLL_DELAY = 200;
// accounting only every 5 log calls so that only one every second (because delay is 200ms) is taken into account
private static final int CALL_RATIO = 5;
@@ -39,7 +39,7 @@ public class WebServerWatcherImpl implements WebServerWatcher {
@Override
public boolean waitForOperational() {
- try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(sharedDir, WEB_SERVER_PROCESS_NUMBER)) {
+ try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(sharedDir, ProcessId.WEB_SERVER.getIpcIndex())) {
if (processCommands.isOperational()) {
return true;
}
diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
index 42527bf4e8b..be0bda6e858 100644
--- a/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
+++ b/server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java
@@ -108,6 +108,7 @@ import org.sonar.server.platform.ServerImpl;
import org.sonar.server.platform.ServerLifecycleNotifier;
import org.sonar.server.platform.ServerLogging;
import org.sonar.server.platform.TempFolderProvider;
+import org.sonar.server.platform.monitoring.JmxConnectorProvider;
import org.sonar.server.plugins.InstalledPluginReferentialFactory;
import org.sonar.server.plugins.ServerExtensionInstaller;
import org.sonar.server.properties.ProjectSettingsFactory;
@@ -138,6 +139,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
private static final Object[] LEVEL_1_COMPONENTS = new Object[] {
ComputeEngineSettings.class,
new SonarQubeVersionProvider(),
+ new JmxConnectorProvider(),
ServerImpl.class,
UuidFactoryImpl.INSTANCE,
// no EmbeddedDatabaseFactory.class, creating H2 DB if responsibility of WebServer
@@ -521,7 +523,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
// SonarQubeMonitor.class, no Monitor in CE, responsibility of Web Server
// EsMonitor.class, no Monitor in CE, responsibility of Web Server
// PluginsMonitor.class, no Monitor in CE, responsibility of Web Server
- // JvmPropertiesMonitor.class, no Monitor in CE, responsibility of Web Server
+ // JvmPropsMonitor.class, no Monitor in CE, responsibility of Web Server
// DatabaseMonitor.class, no Monitor in CE, responsibility of Web Server
// MigrateDbAction.class, no Web Service in CE
// LogsAction.class, no Web Service in CE
diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/app/WebServerWatcherImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/app/WebServerWatcherImplTest.java
index 32007dc60f1..d4a9ae285a4 100644
--- a/server/sonar-ce/src/test/java/org/sonar/ce/app/WebServerWatcherImplTest.java
+++ b/server/sonar-ce/src/test/java/org/sonar/ce/app/WebServerWatcherImplTest.java
@@ -30,12 +30,12 @@ import org.junit.rules.Timeout;
import org.sonar.api.utils.log.LogTester;
import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.process.DefaultProcessCommands;
+import org.sonar.process.ProcessId;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.assertj.core.api.Assertions.assertThat;
public class WebServerWatcherImplTest {
- private static final int WEB_SERVER_PROCESS_NUMBER = 2;
@Rule
public Timeout timeout = Timeout.seconds(1);
@@ -102,7 +102,7 @@ public class WebServerWatcherImplTest {
}
private void setWebServerOperational() {
- try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(sharedDir, WEB_SERVER_PROCESS_NUMBER)) {
+ try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(sharedDir, ProcessId.WEB_SERVER.getIpcIndex())) {
processCommands.setOperational();
}
}
diff --git a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
index b56bd13daf1..291093f2b45 100644
--- a/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
+++ b/server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java
@@ -34,6 +34,7 @@ import org.sonar.db.DbTester;
import org.sonar.process.Props;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH;
import static org.sonar.process.ProcessProperties.PATH_DATA;
import static org.sonar.process.ProcessProperties.PATH_HOME;
import static org.sonar.process.ProcessProperties.PATH_TEMP;
@@ -65,6 +66,7 @@ public class ComputeEngineContainerImplTest {
properties.setProperty(PATH_HOME, homeDir.getAbsolutePath());
properties.setProperty(PATH_DATA, dataDir.getAbsolutePath());
properties.setProperty(PATH_TEMP, tmpDir.getAbsolutePath());
+ properties.setProperty(PROPERTY_SHARED_PATH, tmpDir.getAbsolutePath());
String url = ((BasicDataSource) dbTester.database().getDataSource()).getUrl();
properties.setProperty(DatabaseProperties.PROP_URL, url);
properties.setProperty(DatabaseProperties.PROP_USER, "sonar");
@@ -77,7 +79,7 @@ public class ComputeEngineContainerImplTest {
assertThat(picoContainer.getComponentAdapters())
.hasSize(
CONTAINER_ITSELF
- + 77 // level 4
+ + 78 // level 4
+ 5 // content of CeModule
+ 7 // content of CeQueueModule
+ 4 // content of ReportProcessingModule
@@ -93,7 +95,7 @@ public class ComputeEngineContainerImplTest {
);
assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize(
COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION
- + 22 // level 1
+ + 23 // level 1
+ 47 // content of DaoModule
+ 1 // content of EsSearchModule
+ 56 // content of CorePropertyDefinitions
diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaCommand.java b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaCommand.java
index 6a4f77607d9..98caa87d620 100644
--- a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaCommand.java
+++ b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaCommand.java
@@ -19,10 +19,6 @@
*/
package org.sonar.process.monitor;
-import org.apache.commons.lang.StringUtils;
-
-import javax.annotation.Nullable;
-
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
@@ -30,11 +26,14 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.process.ProcessId;
public class JavaCommand {
// unique key among the group of commands to launch
- private final String key;
+ private final ProcessId id;
private File workDir;
@@ -52,19 +51,12 @@ public class JavaCommand {
private final Map envVariables = new HashMap<>(System.getenv());
- private final int processIndex;
-
- public JavaCommand(String key, int processIndex) {
- this.key = key;
- this.processIndex = processIndex;
- }
-
- public String getKey() {
- return key;
+ public JavaCommand(ProcessId id) {
+ this.id = id;
}
- public int getProcessIndex() {
- return processIndex;
+ public ProcessId getProcessId() {
+ return id;
}
public File getWorkDir() {
diff --git a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java
index 7a5869abb38..c586d7c9df0 100644
--- a/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java
+++ b/server/sonar-process-monitor/src/main/java/org/sonar/process/monitor/JavaProcessLauncher.java
@@ -33,18 +33,24 @@ import org.sonar.process.ProcessCommands;
import org.sonar.process.ProcessEntryPoint;
import org.sonar.process.ProcessUtils;
-public class JavaProcessLauncher {
+import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_INDEX;
+import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_KEY;
+import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH;
+import static org.sonar.process.ProcessEntryPoint.PROPERTY_TERMINATION_TIMEOUT;
+
+class JavaProcessLauncher implements AutoCloseable {
private final Timeouts timeouts;
private final File tempDir;
private final AllProcessesCommands allProcessesCommands;
- public JavaProcessLauncher(Timeouts timeouts, File tempDir) {
+ JavaProcessLauncher(Timeouts timeouts, File tempDir) {
this.timeouts = timeouts;
this.tempDir = tempDir;
this.allProcessesCommands = new AllProcessesCommands(tempDir);
}
+ @Override
public void close() {
allProcessesCommands.close();
}
@@ -52,21 +58,21 @@ public class JavaProcessLauncher {
ProcessRef launch(JavaCommand command) {
Process process = null;
try {
- ProcessCommands commands = allProcessesCommands.createAfterClean(command.getProcessIndex());
+ ProcessCommands commands = allProcessesCommands.createAfterClean(command.getProcessId().getIpcIndex());
ProcessBuilder processBuilder = create(command);
LoggerFactory.getLogger(getClass()).info("Launch process[{}]: {}",
- command.getKey(), StringUtils.join(processBuilder.command(), " "));
+ command.getProcessId().getKey(), StringUtils.join(processBuilder.command(), " "));
process = processBuilder.start();
- StreamGobbler inputGobbler = new StreamGobbler(process.getInputStream(), command.getKey());
+ StreamGobbler inputGobbler = new StreamGobbler(process.getInputStream(), command.getProcessId().getKey());
inputGobbler.start();
- return new ProcessRef(command.getKey(), commands, process, inputGobbler);
+ return new ProcessRef(command.getProcessId().getKey(), commands, process, inputGobbler);
} catch (Exception e) {
// just in case
ProcessUtils.sendKillSignal(process);
- throw new IllegalStateException("Fail to launch " + command.getKey(), e);
+ throw new IllegalStateException("Fail to launch [" + command.getProcessId().getKey() + "]", e);
}
}
@@ -76,6 +82,7 @@ public class JavaProcessLauncher {
commands.addAll(javaCommand.getJavaOptions());
// TODO warning - does it work if temp dir contains a whitespace ?
commands.add(String.format("-Djava.io.tmpdir=%s", tempDir.getAbsolutePath()));
+ commands.add(getJmxAgentCommand());
commands.addAll(buildClasspath(javaCommand));
commands.add(javaCommand.getClassName());
commands.add(buildPropertiesFile(javaCommand).getAbsolutePath());
@@ -88,6 +95,15 @@ public class JavaProcessLauncher {
return processBuilder;
}
+ /**
+ * JVM option to enable the agent that allows inter-process communication through JMX without
+ * opening new ports. The agent is available in JRE of OpenJDK/OracleJDK only.
+ * @see ProcessEntryPoint
+ */
+ private static String getJmxAgentCommand() {
+ return "-javaagent:" + System.getProperty("java.home") + File.separator + "lib" + File.separator + "management-agent.jar";
+ }
+
private String buildJavaPath() {
String separator = System.getProperty("file.separator");
return new File(new File(System.getProperty("java.home")),
@@ -104,12 +120,12 @@ public class JavaProcessLauncher {
propertiesFile = File.createTempFile("sq-process", "properties");
Properties props = new Properties();
props.putAll(javaCommand.getArguments());
- props.setProperty(ProcessEntryPoint.PROPERTY_PROCESS_KEY, javaCommand.getKey());
- props.setProperty(ProcessEntryPoint.PROPERTY_PROCESS_INDEX, Integer.toString(javaCommand.getProcessIndex()));
- props.setProperty(ProcessEntryPoint.PROPERTY_TERMINATION_TIMEOUT, String.valueOf(timeouts.getTerminationTimeout()));
- props.setProperty(ProcessEntryPoint.PROPERTY_SHARED_PATH, tempDir.getAbsolutePath());
+ props.setProperty(PROPERTY_PROCESS_KEY, javaCommand.getProcessId().getKey());
+ props.setProperty(PROPERTY_PROCESS_INDEX, Integer.toString(javaCommand.getProcessId().getIpcIndex()));
+ props.setProperty(PROPERTY_TERMINATION_TIMEOUT, String.valueOf(timeouts.getTerminationTimeout()));
+ props.setProperty(PROPERTY_SHARED_PATH, tempDir.getAbsolutePath());
OutputStream out = new FileOutputStream(propertiesFile);
- props.store(out, String.format("Temporary properties file for command [%s]", javaCommand.getKey()));
+ props.store(out, String.format("Temporary properties file for command [%s]", javaCommand.getProcessId().getKey()));
out.close();
return propertiesFile;
} catch (Exception e) {
diff --git a/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/JavaCommandTest.java b/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/JavaCommandTest.java
index e53c564cdac..c0ddbce5709 100644
--- a/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/JavaCommandTest.java
+++ b/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/JavaCommandTest.java
@@ -25,6 +25,7 @@ import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.util.Properties;
+import org.sonar.process.ProcessId;
import static org.assertj.core.api.Assertions.assertThat;
@@ -32,11 +33,10 @@ public class JavaCommandTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
- private int processIndex = 0;
@Test
public void test_parameters() throws Exception {
- JavaCommand command = new JavaCommand("es", processIndex++);
+ JavaCommand command = new JavaCommand(ProcessId.ELASTICSEARCH);
command.setArgument("first_arg", "val1");
Properties args = new Properties();
@@ -64,7 +64,7 @@ public class JavaCommandTest {
@Test
public void add_java_options() {
- JavaCommand command = new JavaCommand("foo", processIndex++);
+ JavaCommand command = new JavaCommand(ProcessId.ELASTICSEARCH);
assertThat(command.getJavaOptions()).isEmpty();
command.addJavaOptions("");
diff --git a/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/JavaProcessLauncherTest.java b/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/JavaProcessLauncherTest.java
index 499b22a04bd..df9ae973d17 100644
--- a/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/JavaProcessLauncherTest.java
+++ b/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/JavaProcessLauncherTest.java
@@ -23,6 +23,7 @@ import java.io.File;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
+import org.sonar.process.ProcessId;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
@@ -35,7 +36,7 @@ public class JavaProcessLauncherTest {
@Test
public void fail_to_launch() throws Exception {
File tempDir = temp.newFolder();
- JavaCommand command = new JavaCommand("test", 0);
+ JavaCommand command = new JavaCommand(ProcessId.ELASTICSEARCH);
JavaProcessLauncher launcher = new JavaProcessLauncher(new Timeouts(), tempDir);
try {
// command is not correct (missing options), java.lang.ProcessBuilder#start()
@@ -43,7 +44,7 @@ public class JavaProcessLauncherTest {
launcher.launch(command);
fail();
} catch (IllegalStateException e) {
- assertThat(e).hasMessage("Fail to launch test");
+ assertThat(e).hasMessage("Fail to launch [es]");
}
}
}
diff --git a/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/MonitorTest.java b/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/MonitorTest.java
index f278e4978bb..475fe2c0867 100644
--- a/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/MonitorTest.java
+++ b/server/sonar-process-monitor/src/test/java/org/sonar/process/monitor/MonitorTest.java
@@ -42,6 +42,7 @@ import org.junit.rules.TestRule;
import org.junit.rules.Timeout;
import org.sonar.process.Lifecycle.State;
import org.sonar.process.NetworkUtils;
+import org.sonar.process.ProcessId;
import org.sonar.process.SystemExit;
import static java.util.Collections.singletonList;
@@ -147,7 +148,7 @@ public class MonitorTest {
@Test
public void start_then_stop_gracefully() throws Exception {
underTest = newDefaultMonitor(tempDir);
- HttpProcessClient client = new HttpProcessClient(tempDir, "test");
+ HttpProcessClient client = new HttpProcessClient(tempDir, ProcessId.ELASTICSEARCH);
// blocks until started
underTest.start(singletonList(client.newCommand()));
@@ -157,7 +158,7 @@ public class MonitorTest {
// blocks until stopped
underTest.stop();
assertThat(client)
- .isNotReady()
+ .isNotUp()
.wasGracefullyTerminated();
assertThat(underTest.getState()).isEqualTo(State.STOPPED);
verify(fileSystem).reset();
@@ -166,8 +167,8 @@ public class MonitorTest {
@Test
public void start_then_stop_sequence_of_commands() throws Exception {
underTest = newDefaultMonitor(tempDir);
- HttpProcessClient p1 = new HttpProcessClient(tempDir, "p1");
- HttpProcessClient p2 = new HttpProcessClient(tempDir, "p2");
+ HttpProcessClient p1 = new HttpProcessClient(tempDir, ProcessId.ELASTICSEARCH);
+ HttpProcessClient p2 = new HttpProcessClient(tempDir, ProcessId.WEB_SERVER);
underTest.start(Arrays.asList(p1.newCommand(), p2.newCommand()));
// start p2 when p1 is fully started (ready)
@@ -181,10 +182,10 @@ public class MonitorTest {
// stop in inverse order
assertThat(p1)
- .isNotReady()
+ .isNotUp()
.wasGracefullyTerminated();
assertThat(p2)
- .isNotReady()
+ .isNotUp()
.wasGracefullyTerminatedBefore(p1);
verify(fileSystem).reset();
}
@@ -192,8 +193,8 @@ public class MonitorTest {
@Test
public void stop_all_processes_if_monitor_shutdowns() throws Exception {
underTest = newDefaultMonitor(tempDir);
- HttpProcessClient p1 = new HttpProcessClient(tempDir, "p1");
- HttpProcessClient p2 = new HttpProcessClient(tempDir, "p2");
+ HttpProcessClient p1 = new HttpProcessClient(tempDir, ProcessId.ELASTICSEARCH);
+ HttpProcessClient p2 = new HttpProcessClient(tempDir, ProcessId.WEB_SERVER);
underTest.start(Arrays.asList(p1.newCommand(), p2.newCommand()));
assertThat(p1).isUp();
assertThat(p2).isUp();
@@ -211,8 +212,8 @@ public class MonitorTest {
@Test
public void restart_all_processes_if_one_asks_for_restart() throws Exception {
underTest = newDefaultMonitor(tempDir);
- HttpProcessClient p1 = new HttpProcessClient(tempDir, "p1");
- HttpProcessClient p2 = new HttpProcessClient(tempDir, "p2");
+ HttpProcessClient p1 = new HttpProcessClient(tempDir, ProcessId.ELASTICSEARCH);
+ HttpProcessClient p2 = new HttpProcessClient(tempDir, ProcessId.WEB_SERVER);
underTest.start(Arrays.asList(p1.newCommand(), p2.newCommand()));
assertThat(p1).isUp();
@@ -244,8 +245,8 @@ public class MonitorTest {
@Test
public void stop_all_processes_if_one_shutdowns() throws Exception {
underTest = newDefaultMonitor(tempDir);
- HttpProcessClient p1 = new HttpProcessClient(tempDir, "p1");
- HttpProcessClient p2 = new HttpProcessClient(tempDir, "p2");
+ HttpProcessClient p1 = new HttpProcessClient(tempDir, ProcessId.ELASTICSEARCH);
+ HttpProcessClient p2 = new HttpProcessClient(tempDir, ProcessId.WEB_SERVER);
underTest.start(Arrays.asList(p1.newCommand(), p2.newCommand()));
assertThat(p1.isUp()).isTrue();
assertThat(p2.isUp()).isTrue();
@@ -255,10 +256,10 @@ public class MonitorTest {
underTest.awaitTermination();
assertThat(p1)
- .isNotReady()
+ .isNotUp()
.wasNotGracefullyTerminated();
assertThat(p2)
- .isNotReady()
+ .isNotUp()
.wasGracefullyTerminated();
verify(fileSystem).reset();
@@ -267,8 +268,8 @@ public class MonitorTest {
@Test
public void stop_all_processes_if_one_fails_to_start() throws Exception {
underTest = newDefaultMonitor(tempDir);
- HttpProcessClient p1 = new HttpProcessClient(tempDir, "p1");
- HttpProcessClient p2 = new HttpProcessClient(tempDir, "p2", -1);
+ HttpProcessClient p1 = new HttpProcessClient(tempDir, ProcessId.ELASTICSEARCH);
+ HttpProcessClient p2 = new HttpProcessClient(tempDir, ProcessId.WEB_SERVER, -1);
try {
underTest.start(Arrays.asList(p1.newCommand(), p2.newCommand()));
fail();
@@ -286,7 +287,7 @@ public class MonitorTest {
@Test
public void fail_to_start_if_bad_class_name() throws Exception {
underTest = newDefaultMonitor(tempDir);
- JavaCommand command = new JavaCommand("test", processIndex++)
+ JavaCommand command = new JavaCommand(ProcessId.ELASTICSEARCH)
.addClasspath(testJar.getAbsolutePath())
.setClassName("org.sonar.process.test.Unknown");
@@ -304,7 +305,7 @@ public class MonitorTest {
underTest = newDefaultMonitor(tempDir, true);
assertThat(underTest.hardStopWatcher).isNull();
- HttpProcessClient p1 = new HttpProcessClient(tempDir, "p1");
+ HttpProcessClient p1 = new HttpProcessClient(tempDir, ProcessId.COMPUTE_ENGINE);
underTest.start(singletonList(p1.newCommand()));
assertThat(underTest.hardStopWatcher).isNotNull();
@@ -330,24 +331,24 @@ public class MonitorTest {
*/
private class HttpProcessClient {
private final int httpPort;
- private final String commandKey;
+ private final ProcessId processId;
private final File tempDir;
- private HttpProcessClient(File tempDir, String commandKey) throws IOException {
- this(tempDir, commandKey, NetworkUtils.freePort());
+ private HttpProcessClient(File tempDir, ProcessId processId) throws IOException {
+ this(tempDir, processId, NetworkUtils.freePort());
}
/**
* Use httpPort=-1 to make server fail to start
*/
- private HttpProcessClient(File tempDir, String commandKey, int httpPort) throws IOException {
+ private HttpProcessClient(File tempDir, ProcessId processId, int httpPort) throws IOException {
this.tempDir = tempDir;
- this.commandKey = commandKey;
+ this.processId = processId;
this.httpPort = httpPort;
}
JavaCommand newCommand() {
- return new JavaCommand(commandKey, processIndex++)
+ return new JavaCommand(processId)
.addClasspath(testJar.getAbsolutePath())
.setClassName("org.sonar.process.test.HttpProcess")
.setArgument("httpPort", String.valueOf(httpPort));
@@ -490,7 +491,7 @@ public class MonitorTest {
isNotNull();
if (!actual.wasGracefullyTerminated()) {
- failWithMessage("HttpClient %s should have been gracefully terminated", actual.commandKey);
+ failWithMessage("HttpClient %s should have been gracefully terminated", actual.processId.getKey());
}
return this;
@@ -500,7 +501,7 @@ public class MonitorTest {
isNotNull();
if (actual.wasGracefullyTerminated()) {
- failWithMessage("HttpClient %s should not have been gracefully terminated", actual.commandKey);
+ failWithMessage("HttpClient %s should not have been gracefully terminated", actual.processId.getKey());
}
return this;
@@ -530,17 +531,17 @@ public class MonitorTest {
// check condition
if (!actual.isUp()) {
- failWithMessage("HttpClient %s should be up", actual.commandKey);
+ failWithMessage("HttpClient %s should be up", actual.processId.getKey());
}
return this;
}
- public HttpProcessClientAssert isNotReady() {
+ public HttpProcessClientAssert isNotUp() {
isNotNull();
if (actual.isUp()) {
- failWithMessage("HttpClient %s should not be ready", actual.commandKey);
+ failWithMessage("HttpClient %s should not be up", actual.processId.getKey());
}
return this;
@@ -551,7 +552,7 @@ public class MonitorTest {
// check condition
if (!actual.wasReady()) {
- failWithMessage("HttpClient %s should been ready at least once", actual.commandKey);
+ failWithMessage("HttpClient %s should been ready at least once", actual.processId.getKey());
}
return this;
@@ -562,7 +563,7 @@ public class MonitorTest {
// check condition
if (actual.wasReady()) {
- failWithMessage("HttpClient %s should never been ready", actual.commandKey);
+ failWithMessage("HttpClient %s should never been ready", actual.processId.getKey());
}
return this;
@@ -570,7 +571,7 @@ public class MonitorTest {
}
private JavaCommand newStandardProcessCommand() throws IOException {
- return new JavaCommand("standard", processIndex++)
+ return new JavaCommand(ProcessId.ELASTICSEARCH)
.addClasspath(testJar.getAbsolutePath())
.setClassName("org.sonar.process.test.StandardProcess");
}
diff --git a/server/sonar-process/pom.xml b/server/sonar-process/pom.xml
index dad1c57192b..df90101c3c0 100644
--- a/server/sonar-process/pom.xml
+++ b/server/sonar-process/pom.xml
@@ -93,7 +93,19 @@
${skipServerTests}
-
+
+
+
+ org.codehaus.mojo
+ animal-sniffer-maven-plugin
+
+
+ sun.misc.VMSupport
+
+
+
+
+
diff --git a/server/sonar-process/src/main/java/org/sonar/process/AllProcessesCommands.java b/server/sonar-process/src/main/java/org/sonar/process/AllProcessesCommands.java
index a3b0b8364c9..9652aca6795 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/AllProcessesCommands.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/AllProcessesCommands.java
@@ -24,8 +24,11 @@ import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
+import java.nio.charset.StandardCharsets;
import org.apache.commons.io.IOUtils;
+import static java.lang.String.format;
+import static org.apache.commons.lang.StringUtils.rightPad;
import static org.sonar.process.ProcessCommands.MAX_PROCESSES;
/**
@@ -60,14 +63,17 @@ import static org.sonar.process.ProcessCommands.MAX_PROCESSES;
*
*
*/
-public class AllProcessesCommands {
+public class AllProcessesCommands implements AutoCloseable {
private static final int UP_BYTE_OFFSET = 0;
private static final int STOP_BYTE_OFFSET = 1;
private static final int RESTART_BYTE_OFFSET = 2;
private static final int OPERATIONAL_BYTE_OFFSET = 3;
private static final int PING_BYTE_OFFSET = 4;
+ private static final int JMX_URL_BYTE_OFFSET = PING_BYTE_OFFSET + 8;
- private static final int BYTE_LENGTH_FOR_ONE_PROCESS = 1 + 1 + 1 + 1 + 8;
+ private static final int JMX_URL_SIZE_IN_BYTES = 500;
+
+ private static final int BYTE_LENGTH_FOR_ONE_PROCESS = 1 + 1 + 1 + 1 + 8 + JMX_URL_SIZE_IN_BYTES;
// With this shared memory we can handle up to MAX_PROCESSES processes
private static final int MAX_SHARED_MEMORY = BYTE_LENGTH_FOR_ONE_PROCESS * MAX_PROCESSES;
@@ -142,6 +148,19 @@ public class AllProcessesCommands {
return readLong(processNumber, PING_BYTE_OFFSET);
}
+ String getJmxUrl(int processNumber) {
+ byte[] urlBytes = readBytes(processNumber, JMX_URL_BYTE_OFFSET, JMX_URL_SIZE_IN_BYTES);
+ return new String(urlBytes, StandardCharsets.US_ASCII).trim();
+ }
+
+ void setJmxUrl(int processNumber, String jmxUrl) {
+ byte[] urlBytes = rightPad(jmxUrl, JMX_URL_SIZE_IN_BYTES).getBytes(StandardCharsets.US_ASCII);
+ if (urlBytes.length > JMX_URL_SIZE_IN_BYTES) {
+ throw new IllegalArgumentException(format("JMX URL is too long. Max is %d bytes. Got: %s", JMX_URL_SIZE_IN_BYTES, jmxUrl));
+ }
+ writeBytes(processNumber, JMX_URL_BYTE_OFFSET, urlBytes);
+ }
+
/**
* To be executed by monitor process to ask for child process termination
*/
@@ -165,13 +184,14 @@ public class AllProcessesCommands {
writeByte(processNumber, RESTART_BYTE_OFFSET, EMPTY);
}
+ @Override
public void close() {
IOUtils.closeQuietly(sharedMemory);
}
public void checkProcessNumber(int processNumber) {
if (processNumber < 0 || processNumber >= MAX_PROCESSES) {
- throw new IllegalArgumentException(String.format("Process number %s is not valid", processNumber));
+ throw new IllegalArgumentException(format("Process number %s is not valid", processNumber));
}
}
@@ -185,10 +205,26 @@ public class AllProcessesCommands {
mappedByteBuffer.put(offset(processNumber) + offset, value);
}
+ private void writeBytes(int processNumber, int offset, byte[] value) {
+ int bufferOffset = offset(processNumber) + offset;
+ for (int i = 0; i < value.length; i++) {
+ mappedByteBuffer.put(bufferOffset + i, value[i]);
+ }
+ }
+
private byte readByte(int processNumber, int offset) {
return mappedByteBuffer.get(offset(processNumber) + offset);
}
+ private byte[] readBytes(int processNumber, int offset, int length) {
+ int bufferOffset = offset(processNumber) + offset;
+ byte[] bytes = new byte[length];
+ for (int i = 0; i < length; i++) {
+ bytes[i] = mappedByteBuffer.get(bufferOffset + i);
+ }
+ return bytes;
+ }
+
private void writeLong(int processNumber, int offset, long value) {
mappedByteBuffer.putLong(offset(processNumber) + offset, value);
}
@@ -240,6 +276,16 @@ public class AllProcessesCommands {
return AllProcessesCommands.this.getLastPing(processNumber);
}
+ @Override
+ public void setJmxUrl(String s) {
+ AllProcessesCommands.this.setJmxUrl(processNumber, s);
+ }
+
+ @Override
+ public String getJmxUrl() {
+ return AllProcessesCommands.this.getJmxUrl(processNumber);
+ }
+
@Override
public void askForStop() {
AllProcessesCommands.this.askForStop(processNumber);
diff --git a/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java b/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java
index 04a608fef06..d8c9975a4ba 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/DefaultProcessCommands.java
@@ -82,6 +82,16 @@ public class DefaultProcessCommands implements ProcessCommands {
return delegate.getLastPing();
}
+ @Override
+ public void setJmxUrl(String s) {
+ delegate.setJmxUrl(s);
+ }
+
+ @Override
+ public String getJmxUrl() {
+ return delegate.getJmxUrl();
+ }
+
@Override
public void askForStop() {
delegate.askForStop();
diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java
index 482029b81d8..01ece9a7060 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessCommands.java
@@ -33,7 +33,7 @@ import java.io.File;
*/
public interface ProcessCommands extends AutoCloseable {
- int MAX_PROCESSES = 50;
+ int MAX_PROCESSES = 5;
boolean isUp();
@@ -55,6 +55,10 @@ public interface ProcessCommands extends AutoCloseable {
long getLastPing();
+ void setJmxUrl(String s);
+
+ String getJmxUrl();
+
/**
* To be executed by monitor process to ask for child process termination
*/
diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java
index 10930daf679..98190b78e2c 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessEntryPoint.java
@@ -21,6 +21,7 @@ package org.sonar.process;
import java.io.File;
import org.slf4j.LoggerFactory;
+import sun.misc.VMSupport;
public class ProcessEntryPoint implements Stoppable {
@@ -104,6 +105,8 @@ public class ProcessEntryPoint implements Stoppable {
Thread.sleep(20L);
}
+ commands.setJmxUrl(guessJmxUrl());
+
// notify monitor that process is ready
commands.setUp();
@@ -118,6 +121,15 @@ public class ProcessEntryPoint implements Stoppable {
}
}
+ private static String guessJmxUrl() {
+ // this property is set by the agent management-agent.jar enabled by org.sonar.process.monitor.JavaProcessLauncher.
+ String jmxUrl = VMSupport.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress");
+ if (jmxUrl == null) {
+ throw new IllegalStateException("Fail to load the JMX URL of JVM " + System.getProperty("java.vm.name"));
+ }
+ return jmxUrl;
+ }
+
boolean isStarted() {
return lifecycle.getState() == Lifecycle.State.STARTED;
}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessId.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessId.java
new file mode 100644
index 00000000000..9189ada6cd2
--- /dev/null
+++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessId.java
@@ -0,0 +1,53 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process;
+
+public enum ProcessId {
+
+ APP("app", 0), ELASTICSEARCH("es", 1), WEB_SERVER("web", 2), COMPUTE_ENGINE("ce", 3);
+
+ private final String key;
+ private final int ipcIndex;
+
+ ProcessId(String key, int ipcIndex) {
+ this.key = key;
+ this.ipcIndex = ipcIndex;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ /**
+ * Index used for inter-process communication
+ */
+ public int getIpcIndex() {
+ return ipcIndex;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("[");
+ sb.append("key='").append(key).append('\'');
+ sb.append(", ipcIndex=").append(ipcIndex);
+ sb.append(']');
+ return sb.toString();
+ }
+}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/CeDatabaseMBean.java b/server/sonar-process/src/main/java/org/sonar/process/jmx/CeDatabaseMBean.java
new file mode 100644
index 00000000000..354ce0db734
--- /dev/null
+++ b/server/sonar-process/src/main/java/org/sonar/process/jmx/CeDatabaseMBean.java
@@ -0,0 +1,43 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.jmx;
+
+public interface CeDatabaseMBean {
+
+ String OBJECT_NAME = "SonarQube:name=ComputeEngineDatabase";
+
+ int getPoolActiveConnections();
+
+ int getPoolMaxActiveConnections();
+
+ int getPoolIdleConnections();
+
+ int getPoolMaxIdleConnections();
+
+ int getPoolMinIdleConnections();
+
+ int getPoolInitialSize();
+
+ long getPoolMaxWaitMillis();
+
+ boolean getPoolRemoveAbandoned();
+
+ int getPoolRemoveAbandonedTimeoutSeconds();
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/ComputeEngineQueueMonitorMBean.java b/server/sonar-process/src/main/java/org/sonar/process/jmx/CeTasksMBean.java
similarity index 85%
rename from server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/ComputeEngineQueueMonitorMBean.java
rename to server/sonar-process/src/main/java/org/sonar/process/jmx/CeTasksMBean.java
index f1d694ded59..968dabc52b2 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/ComputeEngineQueueMonitorMBean.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/jmx/CeTasksMBean.java
@@ -17,14 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-package org.sonar.server.computation.monitoring;
+package org.sonar.process.jmx;
-public interface ComputeEngineQueueMonitorMBean {
+public interface CeTasksMBean {
- /**
- * Count of received batch reports since instance startup
- */
- long getReceivedCount();
+ String OBJECT_NAME = "SonarQube:name=ComputeEngineTasks";
/**
* Count of batch reports waiting for processing since startup, including reports received before instance startup.
@@ -47,7 +44,7 @@ public interface ComputeEngineQueueMonitorMBean {
long getSuccessCount();
/**
- * Time spent processing reports since startup.
+ * Time spent processing reports since startup, in milliseconds.
*/
long getProcessingTime();
diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/EsSettingsMBean.java b/server/sonar-process/src/main/java/org/sonar/process/jmx/EsSettingsMBean.java
new file mode 100644
index 00000000000..197dc35051c
--- /dev/null
+++ b/server/sonar-process/src/main/java/org/sonar/process/jmx/EsSettingsMBean.java
@@ -0,0 +1,38 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.jmx;
+
+/**
+ * MBean registered in the Elasticsearch process
+ */
+public interface EsSettingsMBean {
+
+ String OBJECT_NAME = "SonarQube:name=ElasticsearchSettings";
+
+ /**
+ * @return the enabled HTTP port, -1 if disabled
+ */
+ int getHttpPort();
+
+ String getClusterName();
+
+ String getNodeName();
+
+}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/Jmx.java b/server/sonar-process/src/main/java/org/sonar/process/jmx/Jmx.java
new file mode 100644
index 00000000000..62375a32e83
--- /dev/null
+++ b/server/sonar-process/src/main/java/org/sonar/process/jmx/Jmx.java
@@ -0,0 +1,86 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.jmx;
+
+import java.lang.management.ManagementFactory;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+import javax.management.StandardMBean;
+import org.slf4j.LoggerFactory;
+
+/**
+ * JMX utilities to register MBeans to JMX server
+ */
+public class Jmx {
+
+ private Jmx() {
+ // only statics
+ }
+
+ /**
+ * Register a MBean to JMX server
+ */
+ public static void register(String name, Object instance) {
+ try {
+ Class mbeanInterface = guessMBeanInterface(instance);
+ ManagementFactory.getPlatformMBeanServer().registerMBean(new StandardMBean(instance, mbeanInterface), new ObjectName(name));
+
+ } catch (MalformedObjectNameException | NotCompliantMBeanException | InstanceAlreadyExistsException | MBeanRegistrationException e) {
+ throw new IllegalStateException("Can not register MBean [" + name + "]", e);
+ }
+ }
+
+ /**
+ * MBeans have multiple conventions, including:
+ * 1. name of interface is suffixed by "MBean"
+ * 2. name of implementation is the name of the interface without "MBean"
+ * 3. implementation and interface must be in the same package
+ * To avoid the last convention, we wrap the mbean within a StandardMBean. That
+ * requires to find the related interface.
+ */
+ private static Class guessMBeanInterface(Object instance) {
+ Class mbeanInterface = null;
+ Class>[] interfaces = instance.getClass().getInterfaces();
+ for (Class> anInterface : interfaces) {
+ if (anInterface.getName().endsWith("MBean")) {
+ mbeanInterface = anInterface;
+ break;
+ }
+ }
+ if (mbeanInterface == null) {
+ throw new IllegalArgumentException("Can not find the MBean interface of class " + instance.getClass().getName());
+ }
+ return mbeanInterface;
+ }
+
+ /**
+ * Unregister a MBean from JMX server. Errors are ignored and logged as warnings.
+ */
+ public static void unregister(String name) {
+ try {
+ ManagementFactory.getPlatformMBeanServer().unregisterMBean(new ObjectName(name));
+ } catch (Exception e) {
+ LoggerFactory.getLogger(Jmx.class).warn("Can not unregister MBean [" + name + "]", e);
+ }
+ }
+}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnection.java b/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnection.java
new file mode 100644
index 00000000000..378c135af03
--- /dev/null
+++ b/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnection.java
@@ -0,0 +1,97 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.jmx;
+
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryUsage;
+import java.lang.management.ThreadMXBean;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import javax.annotation.CheckForNull;
+import javax.management.JMX;
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+
+public class JmxConnection implements AutoCloseable {
+
+ private static final long MEGABYTE = 1024L * 1024L;
+ private final JMXConnector jmxConnector;
+
+ JmxConnection(JMXConnector jmxConnector) {
+ this.jmxConnector = jmxConnector;
+ }
+
+ /**
+ * Get a MBean from a remote JMX server.
+ * @throws IllegalStateException if a valid
+ * connection to remote server cannot be created, for instance because the connection to has
+ * not yet been established (with {@link JMXConnector#connect()}), or it has been closed/broken.
+ */
+ public M getMBean(String mBeanName, Class mBeanInterfaceClass) {
+ try {
+ MBeanServerConnection connection = jmxConnector.getMBeanServerConnection();
+ if (mBeanName.startsWith("java.lang")) {
+ return ManagementFactory.newPlatformMXBeanProxy(connection, mBeanName, mBeanInterfaceClass);
+ }
+ return JMX.newMBeanProxy(connection, new ObjectName(mBeanName), mBeanInterfaceClass);
+ } catch (Exception e) {
+ throw new IllegalStateException("Fail to connect to MBean " + mBeanName, e);
+ }
+ }
+
+ public SortedMap getSystemState() {
+ SortedMap props = new TreeMap<>();
+ MemoryMXBean memory = getMBean(ManagementFactory.MEMORY_MXBEAN_NAME, MemoryMXBean.class);
+ MemoryUsage heap = memory.getHeapMemoryUsage();
+ props.put("Heap Committed (MB)", toMegaBytes(heap.getCommitted()));
+ props.put("Heap Init (MB)", toMegaBytes(heap.getInit()));
+ props.put("Heap Max (MB)", toMegaBytes(heap.getMax()));
+ props.put("Heap Used (MB)", toMegaBytes(heap.getUsed()));
+ MemoryUsage nonHeap = memory.getNonHeapMemoryUsage();
+ props.put("Non Heap Committed (MB)", toMegaBytes(nonHeap.getCommitted()));
+ props.put("Non Heap Init (MB)", toMegaBytes(nonHeap.getInit()));
+ props.put("Non Heap Max (MB)", toMegaBytes(nonHeap.getMax()));
+ props.put("Non Heap Used (MB)", toMegaBytes(nonHeap.getUsed()));
+ ThreadMXBean thread = getMBean(ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class);
+ props.put("Thread Count", thread.getThreadCount());
+ return props;
+ }
+
+ // visible for testing
+ @CheckForNull
+ static Long toMegaBytes(long bytes) {
+ if (bytes < 0L) {
+ return null;
+ }
+ return bytes / MEGABYTE;
+ }
+
+ @Override
+ public void close() {
+ try {
+ jmxConnector.close();
+ } catch (IOException e) {
+ throw new IllegalStateException("Can not close JMX connector", e);
+ }
+ }
+}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnectionFactory.java b/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnectionFactory.java
new file mode 100644
index 00000000000..ca906b9540d
--- /dev/null
+++ b/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnectionFactory.java
@@ -0,0 +1,57 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.jmx;
+
+import java.io.File;
+import javax.annotation.concurrent.Immutable;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+import org.sonar.process.DefaultProcessCommands;
+import org.sonar.process.ProcessEntryPoint;
+import org.sonar.process.ProcessId;
+import org.sonar.process.Props;
+
+/**
+ * Connects to JMX of other JVM processes
+ */
+@Immutable
+public class JmxConnectionFactory {
+ private final File ipcSharedDir;
+
+ public JmxConnectionFactory(File ipcSharedDir) {
+ this.ipcSharedDir = ipcSharedDir;
+ }
+
+ public JmxConnectionFactory(Props props) {
+ this.ipcSharedDir = props.nonNullValueAsFile(ProcessEntryPoint.PROPERTY_SHARED_PATH);
+ }
+
+ public JmxConnection create(ProcessId processId) {
+ try (DefaultProcessCommands commands = DefaultProcessCommands.secondary(ipcSharedDir, processId.getIpcIndex())) {
+ String url = commands.getJmxUrl();
+ JMXConnector jmxConnector = JMXConnectorFactory.newJMXConnector(new JMXServiceURL(url), null);
+ jmxConnector.connect();
+ return new JmxConnection(jmxConnector);
+ } catch (Exception e) {
+ throw new IllegalStateException("Can not connect to process " + processId, e);
+ }
+ }
+}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/package-info.java b/server/sonar-process/src/main/java/org/sonar/process/jmx/package-info.java
new file mode 100644
index 00000000000..bb4fb97207f
--- /dev/null
+++ b/server/sonar-process/src/main/java/org/sonar/process/jmx/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.process.jmx;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-process/src/test/java/org/sonar/process/AllProcessesCommandsTest.java b/server/sonar-process/src/test/java/org/sonar/process/AllProcessesCommandsTest.java
index bda42cf07e7..e834fce905f 100644
--- a/server/sonar-process/src/test/java/org/sonar/process/AllProcessesCommandsTest.java
+++ b/server/sonar-process/src/test/java/org/sonar/process/AllProcessesCommandsTest.java
@@ -96,6 +96,20 @@ public class AllProcessesCommandsTest {
assertThat(readLong(commands, offset)).isGreaterThanOrEqualTo(currentTime);
}
+ @Test
+ public void write_and_read_jmx_url() throws IOException {
+ AllProcessesCommands commands = new AllProcessesCommands(temp.newFolder());
+
+ int offset = 12;
+ for (int i = 0; i < 500; i++) {
+ assertThat(readByte(commands, offset + i)).isEqualTo(EMPTY);
+ }
+
+ commands.setJmxUrl(PROCESS_NUMBER, "jmx:foo");
+ assertThat(readByte(commands, offset)).isNotEqualTo(EMPTY);
+ assertThat(commands.getJmxUrl(PROCESS_NUMBER)).isEqualTo("jmx:foo");
+ }
+
@Test
public void ask_for_stop() throws Exception {
AllProcessesCommands commands = new AllProcessesCommands(temp.newFolder());
diff --git a/server/sonar-process/src/test/java/org/sonar/process/ProcessEntryPointTest.java b/server/sonar-process/src/test/java/org/sonar/process/ProcessEntryPointTest.java
index 6acf205b52e..f6e2bfd916f 100644
--- a/server/sonar-process/src/test/java/org/sonar/process/ProcessEntryPointTest.java
+++ b/server/sonar-process/src/test/java/org/sonar/process/ProcessEntryPointTest.java
@@ -54,6 +54,8 @@ public class ProcessEntryPointTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
+ ProcessCommands commands = mock(ProcessCommands.class);
+
@Test
public void load_properties_from_file() throws Exception {
File propsFile = temp.newFile();
@@ -67,7 +69,7 @@ public class ProcessEntryPointTest {
@Test
public void test_initial_state() throws Exception {
Props props = createProps();
- ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(ProcessCommands.class));
+ ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, commands);
assertThat(entryPoint.getProps()).isSameAs(props);
assertThat(entryPoint.isStarted()).isFalse();
@@ -77,7 +79,7 @@ public class ProcessEntryPointTest {
@Test
public void fail_to_launch_multiple_times() throws IOException {
Props props = createProps();
- ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(ProcessCommands.class));
+ ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, commands);
entryPoint.launch(new NoopProcess());
try {
@@ -91,7 +93,7 @@ public class ProcessEntryPointTest {
@Test
public void launch_then_request_graceful_stop() throws Exception {
Props props = createProps();
- final ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(ProcessCommands.class));
+ final ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, commands);
final StandardProcess process = new StandardProcess();
Thread runner = new Thread() {
@@ -117,7 +119,7 @@ public class ProcessEntryPointTest {
@Test
public void terminate_if_unexpected_shutdown() throws Exception {
Props props = createProps();
- final ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(ProcessCommands.class));
+ final ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, commands);
final StandardProcess process = new StandardProcess();
Thread runner = new Thread() {
@@ -147,7 +149,7 @@ public class ProcessEntryPointTest {
@Test
public void terminate_if_startup_error() throws IOException {
Props props = createProps();
- final ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, mock(ProcessCommands.class));
+ final ProcessEntryPoint entryPoint = new ProcessEntryPoint(props, exit, commands);
final Monitored process = new StartupErrorProcess();
entryPoint.launch(process);
diff --git a/server/sonar-process/src/test/java/org/sonar/process/ProcessIdTest.java b/server/sonar-process/src/test/java/org/sonar/process/ProcessIdTest.java
new file mode 100644
index 00000000000..4eebf2cd124
--- /dev/null
+++ b/server/sonar-process/src/test/java/org/sonar/process/ProcessIdTest.java
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ProcessIdTest {
+
+ @Test
+ public void test_constants() {
+ assertThat(ProcessId.COMPUTE_ENGINE.getKey()).isEqualTo("ce");
+ assertThat(ProcessId.COMPUTE_ENGINE.getIpcIndex()).isEqualTo(3);
+ }
+
+ @Test
+ public void all_values_are_unique() {
+ Set ipcIndices = new HashSet<>();
+ Set keys = new HashSet<>();
+ for (ProcessId processId : ProcessId.values()) {
+ ipcIndices.add(processId.getIpcIndex());
+ keys.add(processId.getKey());
+ }
+ assertThat(ipcIndices).hasSize(ProcessId.values().length);
+ assertThat(keys).hasSize(ProcessId.values().length);
+ }
+}
diff --git a/server/sonar-process/src/test/java/org/sonar/process/jmx/Fake.java b/server/sonar-process/src/test/java/org/sonar/process/jmx/Fake.java
new file mode 100644
index 00000000000..e7bf9912c78
--- /dev/null
+++ b/server/sonar-process/src/test/java/org/sonar/process/jmx/Fake.java
@@ -0,0 +1,27 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.jmx;
+
+public class Fake implements FakeMBean {
+ @Override
+ public void foo() {
+
+ }
+}
diff --git a/server/sonar-process/src/test/java/org/sonar/process/jmx/FakeMBean.java b/server/sonar-process/src/test/java/org/sonar/process/jmx/FakeMBean.java
new file mode 100644
index 00000000000..b5cc660511c
--- /dev/null
+++ b/server/sonar-process/src/test/java/org/sonar/process/jmx/FakeMBean.java
@@ -0,0 +1,24 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.jmx;
+
+public interface FakeMBean {
+ void foo();
+}
diff --git a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionTest.java b/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionTest.java
new file mode 100644
index 00000000000..c8aa351524d
--- /dev/null
+++ b/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionTest.java
@@ -0,0 +1,36 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.jmx;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class JmxConnectionTest {
+
+ @Test
+ public void toMegaBytes() {
+ assertThat(JmxConnection.toMegaBytes(-1)).isNull();
+ assertThat(JmxConnection.toMegaBytes(0L)).isEqualTo(0L);
+ assertThat(JmxConnection.toMegaBytes(500L)).isEqualTo(0L);
+ assertThat(JmxConnection.toMegaBytes(500_000L)).isEqualTo(0L);
+ assertThat(JmxConnection.toMegaBytes(500_000_000L)).isEqualTo(476L);
+ }
+}
diff --git a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTest.java b/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTest.java
new file mode 100644
index 00000000000..9b241accac3
--- /dev/null
+++ b/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTest.java
@@ -0,0 +1,87 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.jmx;
+
+import java.lang.management.ManagementFactory;
+import javax.annotation.CheckForNull;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class JmxTest {
+
+ static final String FAKE_NAME = "SonarQube:name=Fake";
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ FakeMBean mbean = new Fake();
+
+ @Test
+ public void register_and_unregister() throws Exception {
+ assertThat(lookupMBean()).isNull();
+
+ Jmx.register(FAKE_NAME, mbean);
+ assertThat(lookupMBean()).isNotNull();
+
+ Jmx.unregister(FAKE_NAME);
+ assertThat(lookupMBean()).isNull();
+ }
+
+ @Test
+ public void do_not_fail_when_unregistering_a_non_registered_bean() throws Exception {
+ Jmx.unregister(FAKE_NAME);
+ assertThat(lookupMBean()).isNull();
+ }
+
+ @Test
+ public void register_fails_if_mbean_interface_can_not_be_found() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Can not find the MBean interface of class java.lang.String");
+
+ Jmx.register(FAKE_NAME, "not a mbean");
+ }
+
+ @Test
+ public void support_implementation_in_different_package_than_interface() throws Exception {
+ assertThat(lookupMBean()).isNull();
+
+ Jmx.register(FAKE_NAME, new org.sonar.process.jmx.test.Fake());
+ assertThat(lookupMBean()).isNotNull();
+
+ Jmx.unregister(FAKE_NAME);
+ assertThat(lookupMBean()).isNull();
+ }
+
+ @CheckForNull
+ private ObjectInstance lookupMBean() throws Exception {
+ try {
+ return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(FAKE_NAME));
+ } catch (InstanceNotFoundException e) {
+ return null;
+ }
+ }
+
+}
diff --git a/server/sonar-process/src/test/java/org/sonar/process/jmx/test/Fake.java b/server/sonar-process/src/test/java/org/sonar/process/jmx/test/Fake.java
new file mode 100644
index 00000000000..d5e15ab0ca9
--- /dev/null
+++ b/server/sonar-process/src/test/java/org/sonar/process/jmx/test/Fake.java
@@ -0,0 +1,30 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.jmx.test;
+
+import org.sonar.process.jmx.FakeMBean;
+
+// implementation is in a different package than interface
+public class Fake implements FakeMBean {
+ @Override
+ public void foo() {
+
+ }
+}
diff --git a/server/sonar-search/src/main/java/org/sonar/search/SearchSettings.java b/server/sonar-search/src/main/java/org/sonar/search/EsSettings.java
similarity index 88%
rename from server/sonar-search/src/main/java/org/sonar/search/SearchSettings.java
rename to server/sonar-search/src/main/java/org/sonar/search/EsSettings.java
index db634f5c587..2f0986e1e45 100644
--- a/server/sonar-search/src/main/java/org/sonar/search/SearchSettings.java
+++ b/server/sonar-search/src/main/java/org/sonar/search/EsSettings.java
@@ -33,17 +33,18 @@ import org.slf4j.LoggerFactory;
import org.sonar.process.MessageException;
import org.sonar.process.ProcessProperties;
import org.sonar.process.Props;
+import org.sonar.process.jmx.EsSettingsMBean;
-class SearchSettings {
+public class EsSettings implements EsSettingsMBean {
- private static final Logger LOGGER = LoggerFactory.getLogger(SearchSettings.class);
+ private static final Logger LOGGER = LoggerFactory.getLogger(EsSettings.class);
public static final String PROP_MARVEL_HOSTS = "sonar.search.marvelHosts";
private final Props props;
private final Set masterHosts = new LinkedHashSet<>();
- SearchSettings(Props props) {
+ EsSettings(Props props) {
this.props = props;
masterHosts.addAll(Arrays.asList(StringUtils.split(props.value(ProcessProperties.CLUSTER_MASTER_HOST, ""), ",")));
}
@@ -56,6 +57,21 @@ class SearchSettings {
return props.valueAsBoolean(ProcessProperties.CLUSTER_MASTER, false);
}
+ @Override
+ public int getHttpPort() {
+ return props.valueAsInt(ProcessProperties.SEARCH_HTTP_PORT, -1);
+ }
+
+ @Override
+ public String getClusterName() {
+ return props.value(ProcessProperties.CLUSTER_NAME);
+ }
+
+ @Override
+ public String getNodeName() {
+ return props.value(ProcessProperties.CLUSTER_NODE_NAME);
+ }
+
Settings build() {
ImmutableSettings.Builder builder = ImmutableSettings.settingsBuilder();
configureFileSystem(builder);
@@ -115,8 +131,8 @@ class SearchSettings {
// Elasticsearch sets the default value of TCP reuse address to true only on non-MSWindows machines, but why ?
builder.put("network.tcp.reuse_address", true);
- Integer httpPort = props.valueAsInt(ProcessProperties.SEARCH_HTTP_PORT);
- if (httpPort == null || httpPort < 0) {
+ int httpPort = getHttpPort();
+ if (httpPort < 0) {
// standard configuration
builder.put("http.enabled", false);
} else {
@@ -130,7 +146,7 @@ class SearchSettings {
}
}
- private void configureIndexDefaults(ImmutableSettings.Builder builder) {
+ private static void configureIndexDefaults(ImmutableSettings.Builder builder) {
builder
.put("index.number_of_shards", "1")
.put("index.refresh_interval", "30s")
@@ -156,10 +172,11 @@ class SearchSettings {
}
}
builder.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, replicationFactor);
- builder.put("cluster.name", props.value(ProcessProperties.CLUSTER_NAME));
+ builder.put("cluster.name", getClusterName());
builder.put("cluster.routing.allocation.awareness.attributes", "rack_id");
- builder.put("node.rack_id", props.value(ProcessProperties.CLUSTER_NODE_NAME, "unknown"));
- builder.put("node.name", props.value(ProcessProperties.CLUSTER_NODE_NAME));
+ String nodeName = getNodeName();
+ builder.put("node.rack_id", nodeName);
+ builder.put("node.name", nodeName);
}
private void configureMarvel(ImmutableSettings.Builder builder) {
diff --git a/server/sonar-search/src/main/java/org/sonar/search/SearchServer.java b/server/sonar-search/src/main/java/org/sonar/search/SearchServer.java
index 0a7939abedf..31541ad259f 100644
--- a/server/sonar-search/src/main/java/org/sonar/search/SearchServer.java
+++ b/server/sonar-search/src/main/java/org/sonar/search/SearchServer.java
@@ -26,14 +26,16 @@ import org.sonar.process.MinimumViableSystem;
import org.sonar.process.Monitored;
import org.sonar.process.ProcessEntryPoint;
import org.sonar.process.Props;
+import org.sonar.process.jmx.EsSettingsMBean;
+import org.sonar.process.jmx.Jmx;
public class SearchServer implements Monitored {
- private final SearchSettings settings;
+ private final EsSettings settings;
private InternalNode node;
public SearchServer(Props props) {
- this.settings = new SearchSettings(props);
+ this.settings = new EsSettings(props);
new MinimumViableSystem()
.checkJavaVersion()
.checkWritableTempDir();
@@ -41,6 +43,7 @@ public class SearchServer implements Monitored {
@Override
public void start() {
+ Jmx.register(EsSettingsMBean.OBJECT_NAME, settings);
node = new InternalNode(settings.build(), false);
node.start();
}
@@ -70,6 +73,7 @@ public class SearchServer implements Monitored {
if (node != null && !node.isClosed()) {
node.close();
}
+ Jmx.unregister(EsSettingsMBean.OBJECT_NAME);
}
public static void main(String... args) {
diff --git a/server/sonar-search/src/test/java/org/sonar/search/SearchSettingsTest.java b/server/sonar-search/src/test/java/org/sonar/search/EsSettingsTest.java
similarity index 87%
rename from server/sonar-search/src/test/java/org/sonar/search/SearchSettingsTest.java
rename to server/sonar-search/src/test/java/org/sonar/search/EsSettingsTest.java
index 607eab9d92e..f8f12f25272 100644
--- a/server/sonar-search/src/test/java/org/sonar/search/SearchSettingsTest.java
+++ b/server/sonar-search/src/test/java/org/sonar/search/EsSettingsTest.java
@@ -34,7 +34,7 @@ import java.util.Properties;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
-public class SearchSettingsTest {
+public class EsSettingsTest {
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@@ -49,10 +49,10 @@ public class SearchSettingsTest {
props.set(ProcessProperties.CLUSTER_NAME, "tests");
props.set(ProcessProperties.CLUSTER_NODE_NAME, "test");
- SearchSettings searchSettings = new SearchSettings(props);
- assertThat(searchSettings.inCluster()).isFalse();
+ EsSettings esSettings = new EsSettings(props);
+ assertThat(esSettings.inCluster()).isFalse();
- Settings generated = searchSettings.build();
+ Settings generated = esSettings.build();
assertThat(generated.get("transport.tcp.port")).isEqualTo("1234");
assertThat(generated.get("transport.host")).isEqualTo("127.0.0.1");
assertThat(generated.get("cluster.name")).isEqualTo("tests");
@@ -74,10 +74,10 @@ public class SearchSettingsTest {
public void test_default_hosts() throws Exception {
Props props = minProps();
- SearchSettings searchSettings = new SearchSettings(props);
- assertThat(searchSettings.inCluster()).isFalse();
+ EsSettings esSettings = new EsSettings(props);
+ assertThat(esSettings.inCluster()).isFalse();
- Settings generated = searchSettings.build();
+ Settings generated = esSettings.build();
assertThat(generated.get("transport.tcp.port")).isEqualTo("9001");
assertThat(generated.get("transport.host")).isEqualTo("127.0.0.1");
assertThat(generated.get("cluster.name")).isEqualTo("sonarqube");
@@ -94,7 +94,7 @@ public class SearchSettingsTest {
props.set(ProcessProperties.PATH_LOGS, logDir.getAbsolutePath());
props.set(ProcessProperties.PATH_TEMP, tempDir.getAbsolutePath());
- Settings settings = new SearchSettings(props).build();
+ Settings settings = new EsSettings(props).build();
assertThat(settings.get("path.data")).isEqualTo(new File(dataDir, "es").getAbsolutePath());
assertThat(settings.get("path.logs")).isEqualTo(logDir.getAbsolutePath());
@@ -106,7 +106,7 @@ public class SearchSettingsTest {
Props props = minProps();
props.set(ProcessProperties.CLUSTER_ACTIVATE, "true");
props.set(ProcessProperties.CLUSTER_MASTER, "true");
- Settings settings = new SearchSettings(props).build();
+ Settings settings = new EsSettings(props).build();
assertThat(settings.get("index.number_of_replicas")).isEqualTo("1");
assertThat(settings.get("discovery.zen.ping.unicast.hosts")).isNull();
@@ -118,7 +118,7 @@ public class SearchSettingsTest {
Props props = minProps();
props.set(ProcessProperties.CLUSTER_ACTIVATE, "true");
props.set(ProcessProperties.CLUSTER_MASTER_HOST, "127.0.0.2,127.0.0.3");
- Settings settings = new SearchSettings(props).build();
+ Settings settings = new EsSettings(props).build();
assertThat(settings.get("discovery.zen.ping.unicast.hosts")).isEqualTo("127.0.0.2,127.0.0.3");
assertThat(settings.get("node.master")).isEqualTo("false");
@@ -129,7 +129,7 @@ public class SearchSettingsTest {
Props props = minProps();
props.set(ProcessProperties.CLUSTER_ACTIVATE, "true");
try {
- new SearchSettings(props).build();
+ new EsSettings(props).build();
fail();
} catch (MessageException ignored) {
// expected
@@ -139,8 +139,8 @@ public class SearchSettingsTest {
@Test
public void enable_marvel() throws Exception {
Props props = minProps();
- props.set(SearchSettings.PROP_MARVEL_HOSTS, "127.0.0.2,127.0.0.3");
- Settings settings = new SearchSettings(props).build();
+ props.set(EsSettings.PROP_MARVEL_HOSTS, "127.0.0.2,127.0.0.3");
+ Settings settings = new EsSettings(props).build();
assertThat(settings.get("marvel.agent.exporter.es.hosts")).isEqualTo("127.0.0.2,127.0.0.3");
}
@@ -149,7 +149,7 @@ public class SearchSettingsTest {
public void enable_http_connector() throws Exception {
Props props = minProps();
props.set(ProcessProperties.SEARCH_HTTP_PORT, "9010");
- Settings settings = new SearchSettings(props).build();
+ Settings settings = new EsSettings(props).build();
assertThat(settings.get("http.port")).isEqualTo("9010");
assertThat(settings.get("http.host")).isEqualTo("127.0.0.1");
@@ -161,7 +161,7 @@ public class SearchSettingsTest {
Props props = minProps();
props.set(ProcessProperties.SEARCH_HTTP_PORT, "9010");
props.set(ProcessProperties.SEARCH_HOST, "127.0.0.2");
- Settings settings = new SearchSettings(props).build();
+ Settings settings = new EsSettings(props).build();
assertThat(settings.get("http.port")).isEqualTo("9010");
assertThat(settings.get("http.host")).isEqualTo("127.0.0.2");
diff --git a/server/sonar-search/src/test/java/org/sonar/search/SearchServerTest.java b/server/sonar-search/src/test/java/org/sonar/search/SearchServerTest.java
index 5ce6cf13a0b..ebf7e106f4b 100644
--- a/server/sonar-search/src/test/java/org/sonar/search/SearchServerTest.java
+++ b/server/sonar-search/src/test/java/org/sonar/search/SearchServerTest.java
@@ -19,6 +19,8 @@
*/
package org.sonar.search;
+import java.net.InetAddress;
+import java.util.Properties;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.transport.NoNodeAvailableException;
@@ -34,12 +36,10 @@ import org.junit.rules.TemporaryFolder;
import org.junit.rules.TestRule;
import org.junit.rules.Timeout;
import org.sonar.process.NetworkUtils;
+import org.sonar.process.ProcessEntryPoint;
import org.sonar.process.ProcessProperties;
import org.sonar.process.Props;
-import java.net.InetAddress;
-import java.util.Properties;
-
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
@@ -78,6 +78,7 @@ public class SearchServerTest {
props.set(ProcessProperties.CLUSTER_NAME, CLUSTER_NAME);
props.set(ProcessProperties.CLUSTER_NODE_NAME, "test");
props.set(ProcessProperties.PATH_HOME, temp.newFolder().getAbsolutePath());
+ props.set(ProcessEntryPoint.PROPERTY_SHARED_PATH, temp.newFolder().getAbsolutePath());
searchServer = new SearchServer(props);
searchServer.start();
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/CeModule.java b/server/sonar-server/src/main/java/org/sonar/ce/CeModule.java
index f4f05b14fba..1f4bb4b7f35 100644
--- a/server/sonar-server/src/main/java/org/sonar/ce/CeModule.java
+++ b/server/sonar-server/src/main/java/org/sonar/ce/CeModule.java
@@ -20,7 +20,6 @@
package org.sonar.ce;
import org.sonar.ce.log.CeLogging;
-import org.sonar.ce.monitoring.DummyCEQueueStatusImpl;
import org.sonar.ce.queue.CeQueueImpl;
import org.sonar.ce.queue.report.ReportFiles;
import org.sonar.ce.queue.report.ReportSubmitter;
@@ -32,9 +31,6 @@ public class CeModule extends Module {
protected void configureModule() {
add(CeLogging.class,
- // queue monitoring
- DummyCEQueueStatusImpl.class,
-
// Queue
CeQueueImpl.class,
ReportSubmitter.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/monitoring/CEQueueStatus.java b/server/sonar-server/src/main/java/org/sonar/ce/monitoring/CEQueueStatus.java
index 1ffac1e5ffd..695f50c2d47 100644
--- a/server/sonar-server/src/main/java/org/sonar/ce/monitoring/CEQueueStatus.java
+++ b/server/sonar-server/src/main/java/org/sonar/ce/monitoring/CEQueueStatus.java
@@ -21,48 +21,6 @@ package org.sonar.ce.monitoring;
public interface CEQueueStatus {
- /**
- * Sets the count of reports waiting for processing at startup. This method can be called only once.
- *
- * @param initialPendingCount the count of reports, must be {@literal >=} 0
- *
- * @return the new count of batch reports waiting for processing (which is the same as the argument)
- *
- * @throws IllegalStateException if this method has already been called or is called after {@link #getPendingCount()}
- * @throws IllegalArgumentException if the argument is {@literal <} 0
- */
- long initPendingCount(long initialPendingCount);
-
- /**
- * Adds 1 to the count of received batch reports and 1 to the count of batch reports waiting for processing.
- *
- * Calling this method is equivalent to calling {@link #addReceived(long)} with {@code 1} as argument but will
- * trigger no parameter check. So, it can be faster.
- *
- *
- * @return the new count of received batch reports
- *
- * @see #getReceivedCount()
- * @see #getPendingCount()
- *
- * @throws IllegalStateException if {@link #initPendingCount(long)} has not been called yet
- */
- long addReceived();
-
- /**
- * Adds {@code numberOfReceived} to the count of received batch reports and {@code numberOfReceived} to the count of
- * batch reports waiting for processing.
- *
- * @return the new count of received batch reports
- *
- * @see #getReceivedCount()
- * @see #getPendingCount()
- *
- * @throws IllegalStateException if {@link #initPendingCount(long)} has not been called yet
- * @throws IllegalArgumentException if {@code numberOfReceived} is less or equal to 0
- */
- long addReceived(long numberOfReceived);
-
/**
* Adds 1 to the count of batch reports under processing and removes 1 from the count of batch reports waiting for
* processing.
@@ -70,9 +28,6 @@ public interface CEQueueStatus {
* @return the new count of batch reports under processing
*
* @see #getInProgressCount()
- * @see #getPendingCount()
- *
- * @throws IllegalStateException if {@link #initPendingCount(long)} has not been called yet
*/
long addInProgress();
@@ -106,11 +61,6 @@ public interface CEQueueStatus {
*/
long addError(long processingTime);
- /**
- * Count of received batch reports since instance startup
- */
- long getReceivedCount();
-
/**
* Count of batch reports waiting for processing since startup, including reports received before instance startup.
*/
@@ -132,7 +82,7 @@ public interface CEQueueStatus {
long getSuccessCount();
/**
- * Time spent processing batch reports since startup.
+ * Time spent processing batch reports since startup, in milliseconds.
*/
long getProcessingTime();
}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/monitoring/DummyCEQueueStatusImpl.java b/server/sonar-server/src/main/java/org/sonar/ce/monitoring/DummyCEQueueStatusImpl.java
deleted file mode 100644
index 9ed4fcc721a..00000000000
--- a/server/sonar-server/src/main/java/org/sonar/ce/monitoring/DummyCEQueueStatusImpl.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2016 SonarSource SA
- * mailto:contact AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.ce.monitoring;
-
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * FIXME fix this dummy CEQueueStatus implementation, probably by removing its use from
- */
-public class DummyCEQueueStatusImpl implements CEQueueStatus {
- private final AtomicLong received = new AtomicLong(0);
-
- @Override
- public long initPendingCount(long initialPendingCount) {
- return notImplemented();
- }
-
- @Override
- public long addReceived() {
- return received.incrementAndGet();
- }
-
- @Override
- public long addReceived(long numberOfReceived) {
- return received.addAndGet(numberOfReceived);
- }
-
- @Override
- public long addInProgress() {
- return notImplemented();
- }
-
- @Override
- public long addSuccess(long processingTime) {
- return notImplemented();
- }
-
- @Override
- public long addError(long processingTime) {
- return notImplemented();
- }
-
- @Override
- public long getReceivedCount() {
- return received.get();
- }
-
- @Override
- public long getPendingCount() {
- return notImplemented();
- }
-
- @Override
- public long getInProgressCount() {
- return notImplemented();
- }
-
- @Override
- public long getErrorCount() {
- return notImplemented();
- }
-
- @Override
- public long getSuccessCount() {
- return notImplemented();
- }
-
- @Override
- public long getProcessingTime() {
- return notImplemented();
- }
-
- private static long notImplemented() {
- throw new UnsupportedOperationException("Not implemented!");
- }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/ce/queue/CeQueueImpl.java b/server/sonar-server/src/main/java/org/sonar/ce/queue/CeQueueImpl.java
index a6aff101fc0..7aa61ad53ad 100644
--- a/server/sonar-server/src/main/java/org/sonar/ce/queue/CeQueueImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/ce/queue/CeQueueImpl.java
@@ -37,7 +37,6 @@ import org.sonar.db.DbSession;
import org.sonar.db.ce.CeActivityDto;
import org.sonar.db.ce.CeQueueDto;
import org.sonar.db.component.ComponentDto;
-import org.sonar.ce.monitoring.CEQueueStatus;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Predicates.notNull;
@@ -49,7 +48,6 @@ public class CeQueueImpl implements CeQueue {
private final DbClient dbClient;
private final UuidFactory uuidFactory;
- private final CEQueueStatus queueStatus;
private final CeQueueListener[] listeners;
// state
@@ -58,14 +56,13 @@ public class CeQueueImpl implements CeQueue {
/**
* Constructor in case there is no CeQueueListener
*/
- public CeQueueImpl(DbClient dbClient, UuidFactory uuidFactory, CEQueueStatus queueStatus) {
- this(dbClient, uuidFactory, queueStatus, new CeQueueListener[]{});
+ public CeQueueImpl(DbClient dbClient, UuidFactory uuidFactory) {
+ this(dbClient, uuidFactory, new CeQueueListener[] {});
}
- public CeQueueImpl(DbClient dbClient, UuidFactory uuidFactory, CEQueueStatus queueStatus, CeQueueListener[] listeners) {
+ public CeQueueImpl(DbClient dbClient, UuidFactory uuidFactory, CeQueueListener[] listeners) {
this.dbClient = dbClient;
this.uuidFactory = uuidFactory;
- this.queueStatus = queueStatus;
this.listeners = listeners;
}
@@ -83,7 +80,6 @@ public class CeQueueImpl implements CeQueue {
CeQueueDto dto = new CeTaskSubmitToInsertedCeQueueDto(dbSession, dbClient).apply(submission);
CeTask task = loadTask(dbSession, dto);
dbSession.commit();
- queueStatus.addReceived();
return task;
} finally {
@@ -105,7 +101,6 @@ public class CeQueueImpl implements CeQueue {
.toList();
List tasks = loadTasks(dbSession, ceQueueDtos);
dbSession.commit();
- queueStatus.addReceived(tasks.size());
return tasks;
} finally {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/ProcessCommandWrapper.java b/server/sonar-server/src/main/java/org/sonar/server/app/ProcessCommandWrapper.java
index 3310debda32..bb57d8e563e 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/app/ProcessCommandWrapper.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/app/ProcessCommandWrapper.java
@@ -29,4 +29,5 @@ public interface ProcessCommandWrapper {
* Notifies any listening process that the WebServer is operational.
*/
void notifyOperational();
+
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/app/ProcessCommandWrapperImpl.java b/server/sonar-server/src/main/java/org/sonar/server/app/ProcessCommandWrapperImpl.java
index 9936a9f7e93..de29b5607e7 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/app/ProcessCommandWrapperImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/app/ProcessCommandWrapperImpl.java
@@ -37,37 +37,41 @@ public class ProcessCommandWrapperImpl implements ProcessCommandWrapper {
@Override
public void requestSQRestart() {
- call(VoidMethod.ASK_FOR_RESTART);
+ call(VoidMethod.ASK_FOR_RESTART, selfProcessNumber());
}
@Override
public void notifyOperational() {
- call(VoidMethod.SET_OPERATIONAL);
+ call(VoidMethod.SET_OPERATIONAL, selfProcessNumber());
}
- private void call(VoidMethod command) {
+ private int selfProcessNumber() {
+ return nonNullAsInt(PROPERTY_PROCESS_INDEX);
+ }
+
+ private T call(VoidMethod command, int processNumber) {
File shareDir = nonNullValueAsFile(PROPERTY_SHARED_PATH);
- int processNumber = nonNullAsInt(PROPERTY_PROCESS_INDEX);
try (DefaultProcessCommands commands = DefaultProcessCommands.secondary(shareDir, processNumber)) {
- command.callOn(commands);
+ return command.callOn(commands);
}
}
private enum VoidMethod {
SET_OPERATIONAL() {
@Override
- void callOn(ProcessCommands processCommands) {
+ T callOn(ProcessCommands processCommands) {
processCommands.setOperational();
+ return null;
}
},
ASK_FOR_RESTART() {
@Override
- void callOn(ProcessCommands processCommands) {
+ T callOn(ProcessCommands processCommands) {
processCommands.askForRestart();
+ return null;
}
};
-
- abstract void callOn(ProcessCommands processCommands);
+ abstract T callOn(ProcessCommands processCommands);
}
private int nonNullAsInt(String key) {
@@ -76,7 +80,7 @@ public class ProcessCommandWrapperImpl implements ProcessCommandWrapper {
return Integer.parseInt(s);
}
- public File nonNullValueAsFile(String key) {
+ private File nonNullValueAsFile(String key) {
String s = settings.getString(key);
checkArgument(s != null, "Property %s is not set", key);
return new File(s);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/CeModule.java b/server/sonar-server/src/main/java/org/sonar/server/computation/CeModule.java
index 25c04f2e25b..4cdf80747d4 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/CeModule.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/CeModule.java
@@ -25,6 +25,7 @@ import org.sonar.db.purge.period.DefaultPeriodCleaner;
import org.sonar.server.computation.configuration.CeConfigurationImpl;
import org.sonar.server.computation.dbcleaner.IndexPurgeListener;
import org.sonar.server.computation.dbcleaner.ProjectCleaner;
+import org.sonar.server.computation.monitoring.CeDatabaseMBeanImpl;
/**
* Globally available components in CE
@@ -35,6 +36,7 @@ public class CeModule extends Module {
add(
CeConfigurationImpl.class,
CeLogging.class,
+ CeDatabaseMBeanImpl.class,
DefaultPeriodCleaner.class,
ProjectCleaner.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CEQueueStatusImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CEQueueStatusImpl.java
index d9e61e25e15..90a5074f6c2 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CEQueueStatusImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CEQueueStatusImpl.java
@@ -21,86 +21,53 @@ package org.sonar.server.computation.monitoring;
import java.util.concurrent.atomic.AtomicLong;
import org.sonar.ce.monitoring.CEQueueStatus;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeQueueDto;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
public class CEQueueStatusImpl implements CEQueueStatus {
- private static final long PENDING_INITIAL_VALUE = Long.MIN_VALUE;
- private final AtomicLong received = new AtomicLong(0);
- private final AtomicLong pending = new AtomicLong(PENDING_INITIAL_VALUE);
+ private final DbClient dbClient;
private final AtomicLong inProgress = new AtomicLong(0);
private final AtomicLong error = new AtomicLong(0);
private final AtomicLong success = new AtomicLong(0);
private final AtomicLong processingTime = new AtomicLong(0);
- @Override
- public long initPendingCount(long initialPendingCount) {
- checkArgument(initialPendingCount >= 0, "Initial pending count must be >= 0");
- checkState(
- pending.compareAndSet(PENDING_INITIAL_VALUE, initialPendingCount),
- "Method initPendingCount must be used before any other method and can not be called twice");
- return initialPendingCount;
- }
-
- @Override
- public long addReceived() {
- ensurePendingInitialized("addReceived");
-
- pending.incrementAndGet();
- return received.incrementAndGet();
- }
-
- @Override
- public long addReceived(long numberOfReceived) {
- ensurePendingInitialized("addReceived");
- checkArgument(numberOfReceived > 0, "numberOfReceived must be > 0");
-
- pending.addAndGet(numberOfReceived);
- return received.addAndGet(numberOfReceived);
+ public CEQueueStatusImpl(DbClient dbClient) {
+ this.dbClient = dbClient;
}
@Override
public long addInProgress() {
- ensurePendingInitialized("addInProgress");
-
- pending.decrementAndGet();
return inProgress.incrementAndGet();
}
- private void ensurePendingInitialized(String methodName) {
- checkState(pending.get() != PENDING_INITIAL_VALUE, "Method initPendingCount must be used before %s can be called", methodName);
- }
-
@Override
- public long addError(long processingTime) {
- addProcessingTime(processingTime);
+ public long addError(long processingTimeInMs) {
+ addProcessingTime(processingTimeInMs);
inProgress.decrementAndGet();
return error.incrementAndGet();
}
@Override
- public long addSuccess(long processingTime) {
- addProcessingTime(processingTime);
+ public long addSuccess(long processingTimeInMs) {
+ addProcessingTime(processingTimeInMs);
inProgress.decrementAndGet();
return success.incrementAndGet();
}
- private void addProcessingTime(long time) {
- checkArgument(time >= 0, "Processing time can not be < 0");
- processingTime.addAndGet(time);
- }
-
- @Override
- public long getReceivedCount() {
- return received.get();
+ private void addProcessingTime(long ms) {
+ checkArgument(ms >= 0, "Processing time can not be < 0");
+ processingTime.addAndGet(ms);
}
@Override
public long getPendingCount() {
- long currentValue = pending.get();
- return currentValue == PENDING_INITIAL_VALUE ? 0 : currentValue;
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ return dbClient.ceQueueDao().countByStatus(dbSession, CeQueueDto.Status.PENDING);
+ }
}
@Override
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeDatabaseMBeanImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeDatabaseMBeanImpl.java
new file mode 100644
index 00000000000..4b7e43a3fa5
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeDatabaseMBeanImpl.java
@@ -0,0 +1,97 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.computation.monitoring;
+
+import org.apache.commons.dbcp.BasicDataSource;
+import org.picocontainer.Startable;
+import org.sonar.db.DbClient;
+import org.sonar.process.jmx.CeDatabaseMBean;
+import org.sonar.process.jmx.Jmx;
+
+public class CeDatabaseMBeanImpl implements CeDatabaseMBean, Startable {
+ private final DbClient dbClient;
+
+ public CeDatabaseMBeanImpl(DbClient dbClient) {
+ this.dbClient = dbClient;
+ }
+
+ @Override
+ public void start() {
+ Jmx.register(OBJECT_NAME, this);
+ }
+
+ /**
+ * Unregister, if needed
+ */
+ @Override
+ public void stop() {
+ Jmx.unregister(OBJECT_NAME);
+ }
+
+ @Override
+ public int getPoolActiveConnections() {
+ return commonsDbcp().getNumActive();
+ }
+
+ @Override
+ public int getPoolMaxActiveConnections() {
+ return commonsDbcp().getMaxActive();
+ }
+
+ @Override
+ public int getPoolIdleConnections() {
+ return commonsDbcp().getNumIdle();
+ }
+
+ @Override
+ public int getPoolMaxIdleConnections() {
+ return commonsDbcp().getMaxIdle();
+ }
+
+ @Override
+ public int getPoolMinIdleConnections() {
+ return commonsDbcp().getMinIdle();
+ }
+
+ @Override
+ public int getPoolInitialSize() {
+ return commonsDbcp().getInitialSize();
+ }
+
+ @Override
+ public long getPoolMaxWaitMillis() {
+ return commonsDbcp().getMaxWait();
+ }
+
+ @Override
+ public boolean getPoolRemoveAbandoned() {
+ return commonsDbcp().getRemoveAbandoned();
+ }
+
+ @Override
+ public int getPoolRemoveAbandonedTimeoutSeconds() {
+ return commonsDbcp().getRemoveAbandonedTimeout();
+ }
+
+ private BasicDataSource commonsDbcp() {
+ return (BasicDataSource) dbClient.getDatabase().getDataSource();
+ }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/ComputeEngineQueueMonitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeTasksMBeanImpl.java
similarity index 59%
rename from server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/ComputeEngineQueueMonitor.java
rename to server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeTasksMBeanImpl.java
index 94d2322dc1c..57b08e356de 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/ComputeEngineQueueMonitor.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeTasksMBeanImpl.java
@@ -19,47 +19,32 @@
*/
package org.sonar.server.computation.monitoring;
-import java.util.LinkedHashMap;
+import org.picocontainer.Startable;
import org.sonar.ce.monitoring.CEQueueStatus;
+import org.sonar.process.jmx.CeTasksMBean;
+import org.sonar.process.jmx.Jmx;
import org.sonar.server.computation.configuration.CeConfiguration;
-import org.sonar.ce.queue.CeQueue;
-import org.sonar.server.platform.monitoring.BaseMonitorMBean;
-public class ComputeEngineQueueMonitor extends BaseMonitorMBean implements ComputeEngineQueueMonitorMBean {
+public class CeTasksMBeanImpl implements CeTasksMBean, Startable {
private final CEQueueStatus queueStatus;
private final CeConfiguration ceConfiguration;
- public ComputeEngineQueueMonitor(CEQueueStatus queueStatus,
- // ReportQueue initializes CEQueueStatus and is therefor a dependency of
- // ComputeEngineQueueMonitor.
- // Do not remove this parameter, it ensures start order of components
- CeQueue ceQueue,
- CeConfiguration ceConfiguration) {
+ public CeTasksMBeanImpl(CEQueueStatus queueStatus, CeConfiguration ceConfiguration) {
this.queueStatus = queueStatus;
this.ceConfiguration = ceConfiguration;
}
@Override
- public String name() {
- return "ComputeEngine";
+ public void start() {
+ Jmx.register(OBJECT_NAME, this);
}
+ /**
+ * Unregister, if needed
+ */
@Override
- public LinkedHashMap attributes() {
- LinkedHashMap attributes = new LinkedHashMap<>();
- attributes.put("Received", getReceivedCount());
- attributes.put("Pending", getPendingCount());
- attributes.put("In progress", getInProgressCount());
- attributes.put("Successfully processed", getSuccessCount());
- attributes.put("Processed with error", getErrorCount());
- attributes.put("Processing time", getProcessingTime());
- attributes.put("Worker count", getWorkerCount());
- return attributes;
- }
-
- @Override
- public long getReceivedCount() {
- return queueStatus.getReceivedCount();
+ public void stop() {
+ Jmx.unregister(OBJECT_NAME);
}
@Override
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueInitializer.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueInitializer.java
index b6f277f8f8f..eaa67a7fc5d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueInitializer.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueInitializer.java
@@ -24,7 +24,6 @@ import org.sonar.api.platform.ServerStartHandler;
import org.sonar.api.server.ServerSide;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
-import org.sonar.ce.monitoring.CEQueueStatus;
import org.sonar.server.computation.taskprocessor.CeProcessingScheduler;
/**
@@ -36,14 +35,12 @@ import org.sonar.server.computation.taskprocessor.CeProcessingScheduler;
public class CeQueueInitializer implements ServerStartHandler {
private final DbClient dbClient;
- private final CEQueueStatus queueStatus;
private final CeQueueCleaner cleaner;
private final CeProcessingScheduler scheduler;
private boolean done = false;
- public CeQueueInitializer(DbClient dbClient, CEQueueStatus queueStatus, CeQueueCleaner cleaner, CeProcessingScheduler scheduler) {
+ public CeQueueInitializer(DbClient dbClient, CeQueueCleaner cleaner, CeProcessingScheduler scheduler) {
this.dbClient = dbClient;
- this.queueStatus = queueStatus;
this.cleaner = cleaner;
this.scheduler = scheduler;
}
@@ -59,7 +56,6 @@ public class CeQueueInitializer implements ServerStartHandler {
private void initCe() {
DbSession dbSession = dbClient.openSession(false);
try {
- initJmxCounters(dbSession);
cleaner.clean(dbSession);
scheduler.startScheduling();
@@ -67,8 +63,4 @@ public class CeQueueInitializer implements ServerStartHandler {
dbClient.closeSession(dbSession);
}
}
-
- private void initJmxCounters(DbSession dbSession) {
- queueStatus.initPendingCount(dbClient.ceQueueDao().countAll(dbSession));
- }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueModule.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueModule.java
index 4be44d6936b..77b676f7dfc 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueModule.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/CeQueueModule.java
@@ -19,11 +19,11 @@
*/
package org.sonar.server.computation.queue;
-import org.sonar.server.computation.queue.report.CleanReportQueueListener;
import org.sonar.ce.queue.report.ReportFiles;
import org.sonar.core.platform.Module;
import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
-import org.sonar.server.computation.monitoring.ComputeEngineQueueMonitor;
+import org.sonar.server.computation.monitoring.CeTasksMBeanImpl;
+import org.sonar.server.computation.queue.report.CleanReportQueueListener;
public class CeQueueModule extends Module {
@Override
@@ -34,7 +34,7 @@ public class CeQueueModule extends Module {
// queue monitoring
CEQueueStatusImpl.class,
- ComputeEngineQueueMonitor.class,
+ CeTasksMBeanImpl.class,
// queue cleaning
CeQueueCleaner.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/InternalCeQueueImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/InternalCeQueueImpl.java
index d8b10f5c5d3..3e0f988270a 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/queue/InternalCeQueueImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/queue/InternalCeQueueImpl.java
@@ -24,6 +24,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.Nullable;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.System2;
+import org.sonar.ce.monitoring.CEQueueStatus;
import org.sonar.ce.queue.CeQueueImpl;
import org.sonar.ce.queue.CeQueueListener;
import org.sonar.ce.queue.CeTask;
@@ -33,7 +34,6 @@ import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.ce.CeActivityDto;
import org.sonar.db.ce.CeQueueDto;
-import org.sonar.ce.monitoring.CEQueueStatus;
import static java.lang.String.format;
@@ -49,7 +49,7 @@ public class InternalCeQueueImpl extends CeQueueImpl implements InternalCeQueue
public InternalCeQueueImpl(System2 system2, DbClient dbClient, UuidFactory uuidFactory,
CEQueueStatus queueStatus, CeQueueListener[] listeners) {
- super(dbClient, uuidFactory, queueStatus, listeners);
+ super(dbClient, uuidFactory, listeners);
this.system2 = system2;
this.dbClient = dbClient;
this.queueStatus = queueStatus;
@@ -114,12 +114,12 @@ public class InternalCeQueueImpl extends CeQueueImpl implements InternalCeQueue
return;
}
activityDto.setExecutedAt(system2.now());
- long executionTime = activityDto.getExecutedAt() - startedAt;
- activityDto.setExecutionTimeMs(executionTime);
+ long executionTimeInMs = activityDto.getExecutedAt() - startedAt;
+ activityDto.setExecutionTimeMs(executionTimeInMs);
if (status == CeActivityDto.Status.SUCCESS) {
- queueStatus.addSuccess(executionTime);
+ queueStatus.addSuccess(executionTimeInMs);
} else {
- queueStatus.addError(executionTime);
+ queueStatus.addError(executionTimeInMs);
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/BaseMonitorMBean.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/BaseMonitorMBean.java
index bbc8ef67e6e..b56d9a9346e 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/BaseMonitorMBean.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/BaseMonitorMBean.java
@@ -20,17 +20,10 @@
package org.sonar.server.platform.monitoring;
import org.picocontainer.Startable;
-
-import javax.management.InstanceNotFoundException;
-import javax.management.MBeanRegistrationException;
-import javax.management.MalformedObjectNameException;
-import javax.management.ObjectName;
-import javax.management.OperationsException;
-
-import java.lang.management.ManagementFactory;
+import org.sonar.process.jmx.Jmx;
/**
- * Base implementation of {@link org.sonar.server.platform.monitoring.Monitor}
+ * Base implementation of a {@link org.sonar.server.platform.monitoring.Monitor}
* that is exported as a JMX bean
*/
public abstract class BaseMonitorMBean implements Monitor, Startable {
@@ -40,11 +33,7 @@ public abstract class BaseMonitorMBean implements Monitor, Startable {
*/
@Override
public void start() {
- try {
- ManagementFactory.getPlatformMBeanServer().registerMBean(this, objectName());
- } catch (OperationsException | MBeanRegistrationException e) {
- throw new IllegalStateException("Fail to register MBean " + name(), e);
- }
+ Jmx.register(objectName(), this);
}
/**
@@ -52,16 +41,10 @@ public abstract class BaseMonitorMBean implements Monitor, Startable {
*/
@Override
public void stop() {
- try {
- ManagementFactory.getPlatformMBeanServer().unregisterMBean(objectName());
- } catch (InstanceNotFoundException ignored) {
- // ignore, was not correctly started
- } catch (Exception e) {
- throw new IllegalStateException("Fail to unregister MBean " + name(), e);
- }
+ Jmx.unregister(objectName());
}
- ObjectName objectName() throws MalformedObjectNameException {
- return new ObjectName(String.format("SonarQube:name=%s", name()));
+ String objectName() {
+ return "SonarQube:name=" + name();
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeDatabaseMonitor.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeDatabaseMonitor.java
new file mode 100644
index 00000000000..1b6b548e379
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeDatabaseMonitor.java
@@ -0,0 +1,58 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import java.util.LinkedHashMap;
+import org.sonar.process.ProcessId;
+import org.sonar.process.jmx.CeDatabaseMBean;
+import org.sonar.process.jmx.JmxConnection;
+import org.sonar.process.jmx.JmxConnectionFactory;
+
+public class CeDatabaseMonitor implements Monitor {
+
+ private final JmxConnectionFactory jmxConnectionFactory;
+
+ public CeDatabaseMonitor(JmxConnectionFactory jmxConnectionFactory) {
+ this.jmxConnectionFactory = jmxConnectionFactory;
+ }
+
+ @Override
+ public String name() {
+ return "Compute Engine Database";
+ }
+
+ @Override
+ public LinkedHashMap attributes() {
+ try (JmxConnection connection = jmxConnectionFactory.create(ProcessId.COMPUTE_ENGINE)) {
+ LinkedHashMap result = new LinkedHashMap<>();
+ CeDatabaseMBean mbean = connection.getMBean(CeDatabaseMBean.OBJECT_NAME, CeDatabaseMBean.class);
+ result.put("Pool Initial Size", mbean.getPoolInitialSize());
+ result.put("Pool Active Connections", mbean.getPoolActiveConnections());
+ result.put("Pool Idle Connections", mbean.getPoolIdleConnections());
+ result.put("Pool Max Active Connections", mbean.getPoolMaxActiveConnections());
+ result.put("Pool Max Idle Connections", mbean.getPoolMaxIdleConnections());
+ result.put("Pool Min Idle Connections", mbean.getPoolMinIdleConnections());
+ result.put("Pool Max Wait (ms)", mbean.getPoolMaxWaitMillis());
+ result.put("Pool Remove Abandoned", mbean.getPoolRemoveAbandoned());
+ result.put("Pool Remove Abandoned Timeout (sec)", mbean.getPoolRemoveAbandonedTimeoutSeconds());
+ return result;
+ }
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeStateMonitor.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeStateMonitor.java
new file mode 100644
index 00000000000..2c834fe20b7
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeStateMonitor.java
@@ -0,0 +1,46 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import java.util.LinkedHashMap;
+import org.sonar.process.ProcessId;
+import org.sonar.process.jmx.JmxConnection;
+import org.sonar.process.jmx.JmxConnectionFactory;
+
+public class CeStateMonitor implements Monitor {
+
+ private final JmxConnectionFactory jmxConnectionFactory;
+
+ public CeStateMonitor(JmxConnectionFactory jmxConnectionFactory) {
+ this.jmxConnectionFactory = jmxConnectionFactory;
+ }
+
+ @Override
+ public String name() {
+ return "Compute Engine State";
+ }
+
+ @Override
+ public LinkedHashMap attributes() {
+ try (JmxConnection connection = jmxConnectionFactory.create(ProcessId.COMPUTE_ENGINE)) {
+ return new LinkedHashMap<>(connection.getSystemState());
+ }
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeTasksMonitor.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeTasksMonitor.java
new file mode 100644
index 00000000000..77c1af84c53
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeTasksMonitor.java
@@ -0,0 +1,55 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import java.util.LinkedHashMap;
+import org.sonar.process.ProcessId;
+import org.sonar.process.jmx.CeTasksMBean;
+import org.sonar.process.jmx.JmxConnection;
+import org.sonar.process.jmx.JmxConnectionFactory;
+
+public class CeTasksMonitor implements Monitor {
+
+ private final JmxConnectionFactory jmxConnectionFactory;
+
+ public CeTasksMonitor(JmxConnectionFactory jmxConnectionFactory) {
+ this.jmxConnectionFactory = jmxConnectionFactory;
+ }
+
+ @Override
+ public String name() {
+ return "Compute Engine Tasks";
+ }
+
+ @Override
+ public LinkedHashMap attributes() {
+ try (JmxConnection connection = jmxConnectionFactory.create(ProcessId.COMPUTE_ENGINE)) {
+ LinkedHashMap result = new LinkedHashMap<>();
+ CeTasksMBean ceMBean = connection.getMBean(CeTasksMBean.OBJECT_NAME, CeTasksMBean.class);
+ result.put("Pending", ceMBean.getPendingCount());
+ result.put("In Progress", ceMBean.getInProgressCount());
+ result.put("Processed With Success", ceMBean.getSuccessCount());
+ result.put("Processed With Error", ceMBean.getErrorCount());
+ result.put("Processing Time (ms)", ceMBean.getProcessingTime());
+ result.put("Worker Count", ceMBean.getWorkerCount());
+ return result;
+ }
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/DatabaseMonitor.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/DatabaseMonitor.java
index cdadf46aa1a..ceb0caf6ff0 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/DatabaseMonitor.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/DatabaseMonitor.java
@@ -19,18 +19,17 @@
*/
package org.sonar.server.platform.monitoring;
-import org.apache.commons.dbcp.BasicDataSource;
-import org.apache.commons.dbutils.DbUtils;
-import org.sonar.db.version.DatabaseVersion;
-import org.sonar.db.DbSession;
-import org.sonar.db.MyBatis;
-import org.sonar.db.DbClient;
-
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;
+import org.apache.commons.dbcp.BasicDataSource;
+import org.apache.commons.dbutils.DbUtils;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.MyBatis;
+import org.sonar.db.version.DatabaseVersion;
/**
* Information about database and connection pool
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsMonitor.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsMonitor.java
index 470676bdd76..0317ba2c1b0 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsMonitor.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsMonitor.java
@@ -27,22 +27,29 @@ import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
import org.elasticsearch.action.admin.indices.stats.IndexStats;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
+import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.breaker.CircuitBreaker;
+import org.sonar.process.ProcessId;
+import org.sonar.process.jmx.EsSettingsMBean;
+import org.sonar.process.jmx.JmxConnection;
+import org.sonar.process.jmx.JmxConnectionFactory;
import org.sonar.server.es.EsClient;
import static org.apache.commons.io.FileUtils.byteCountToDisplaySize;
public class EsMonitor extends BaseMonitorMBean implements EsMonitorMBean {
+ private final JmxConnectionFactory jmxConnectionFactory;
private final EsClient esClient;
- public EsMonitor(EsClient esClient) {
+ public EsMonitor(JmxConnectionFactory jmxConnectionFactory, EsClient esClient) {
+ this.jmxConnectionFactory = jmxConnectionFactory;
this.esClient = esClient;
}
@Override
public String name() {
- return "ElasticSearch";
+ return "Elasticsearch";
}
/**
@@ -66,6 +73,13 @@ public class EsMonitor extends BaseMonitorMBean implements EsMonitorMBean {
@Override
public LinkedHashMap attributes() {
LinkedHashMap attributes = new LinkedHashMap<>();
+
+ try (JmxConnection connection = jmxConnectionFactory.create(ProcessId.ELASTICSEARCH)) {
+ EsSettingsMBean mbean = connection.getMBean(EsSettingsMBean.OBJECT_NAME, EsSettingsMBean.class);
+ attributes.put("Cluster Name", mbean.getClusterName());
+ attributes.put("Node Name", mbean.getNodeName());
+ attributes.put("HTTP Port", mbean.getHttpPort());
+ }
attributes.put("State", getStateAsEnum());
attributes.put("Indices", indexAttributes());
attributes.put("Number of Nodes", getNumberOfNodes());
@@ -96,10 +110,11 @@ public class EsMonitor extends BaseMonitorMBean implements EsMonitorMBean {
for (Map.Entry entry : nodesStats.getNodesMap().entrySet()) {
LinkedHashMap nodeAttributes = new LinkedHashMap<>();
- nodes.put(entry.getKey(), nodeAttributes);
NodeStats stats = entry.getValue();
- nodeAttributes.put("Address", stats.getNode().getAddress().toString());
- nodeAttributes.put("Type", stats.getNode().isMasterNode() ? "Master" : "Slave");
+ DiscoveryNode node = stats.getNode();
+ nodes.put(node.getName(), nodeAttributes);
+ nodeAttributes.put("Address", node.getAddress().toString());
+ nodeAttributes.put("Type", node.isMasterNode() ? "Master" : "Slave");
nodeAttributes.put("Disk Available", byteCountToDisplaySize(stats.getFs().getTotal().getAvailable().bytes()));
nodeAttributes.put("Store Size", byteCountToDisplaySize(stats.getIndices().getStore().getSizeInBytes()));
nodeAttributes.put("Open Files", stats.getProcess().getOpenFileDescriptors());
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStateMonitor.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStateMonitor.java
new file mode 100644
index 00000000000..0f8d60c4b07
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStateMonitor.java
@@ -0,0 +1,46 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import java.util.LinkedHashMap;
+import org.sonar.process.ProcessId;
+import org.sonar.process.jmx.JmxConnection;
+import org.sonar.process.jmx.JmxConnectionFactory;
+
+public class EsStateMonitor implements Monitor {
+
+ private final JmxConnectionFactory jmxConnectionFactory;
+
+ public EsStateMonitor(JmxConnectionFactory jmxConnectionFactory) {
+ this.jmxConnectionFactory = jmxConnectionFactory;
+ }
+
+ @Override
+ public String name() {
+ return "Elasticsearch State";
+ }
+
+ @Override
+ public LinkedHashMap attributes() {
+ try (JmxConnection connection = jmxConnectionFactory.create(ProcessId.ELASTICSEARCH)) {
+ return new LinkedHashMap<>(connection.getSystemState());
+ }
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JmxConnectorProvider.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JmxConnectorProvider.java
new file mode 100644
index 00000000000..2bc9d247607
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JmxConnectorProvider.java
@@ -0,0 +1,46 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import java.io.File;
+import org.picocontainer.injectors.ProviderAdapter;
+import org.sonar.api.config.Settings;
+import org.sonar.process.jmx.JmxConnectionFactory;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH;
+
+public class JmxConnectorProvider extends ProviderAdapter {
+
+ private JmxConnectionFactory singleton = null;
+
+ public synchronized JmxConnectionFactory provide(Settings settings) {
+ if (singleton == null) {
+ singleton = new JmxConnectionFactory(nonNullValueAsFile(settings, PROPERTY_SHARED_PATH));
+ }
+ return singleton;
+ }
+
+ private static File nonNullValueAsFile(Settings settings, String key) {
+ String s = settings.getString(key);
+ checkArgument(s != null, "Property %s is not set", key);
+ return new File(s);
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JvmPropertiesMonitor.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JvmPropsMonitor.java
similarity index 96%
rename from server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JvmPropertiesMonitor.java
rename to server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JvmPropsMonitor.java
index 0a0a8f8cb9c..3d4b33e292b 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JvmPropertiesMonitor.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JvmPropsMonitor.java
@@ -20,13 +20,12 @@
package org.sonar.server.platform.monitoring;
import com.google.common.collect.Maps;
-
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.SortedMap;
-public class JvmPropertiesMonitor implements Monitor {
+public class JvmPropsMonitor implements Monitor {
@Override
public String name() {
return "JvmProperties";
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
index 84e8156aa3c..7a39ad8281a 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java
@@ -158,9 +158,14 @@ import org.sonar.server.permission.ws.PermissionsWsModule;
import org.sonar.server.platform.BackendCleanup;
import org.sonar.server.platform.ServerLogging;
import org.sonar.server.platform.SettingsChangeNotifier;
+import org.sonar.server.platform.monitoring.CeDatabaseMonitor;
+import org.sonar.server.platform.monitoring.CeStateMonitor;
+import org.sonar.server.platform.monitoring.CeTasksMonitor;
import org.sonar.server.platform.monitoring.DatabaseMonitor;
import org.sonar.server.platform.monitoring.EsMonitor;
-import org.sonar.server.platform.monitoring.JvmPropertiesMonitor;
+import org.sonar.server.platform.monitoring.EsStateMonitor;
+import org.sonar.server.platform.monitoring.JmxConnectorProvider;
+import org.sonar.server.platform.monitoring.JvmPropsMonitor;
import org.sonar.server.platform.monitoring.PluginsMonitor;
import org.sonar.server.platform.monitoring.SonarQubeMonitor;
import org.sonar.server.platform.monitoring.SystemMonitor;
@@ -658,6 +663,7 @@ public class PlatformLevel4 extends PlatformLevel {
TypeValidationModule.class,
// System
+ new JmxConnectorProvider(),
ServerLogging.class,
RestartAction.class,
InfoAction.class,
@@ -668,8 +674,12 @@ public class PlatformLevel4 extends PlatformLevel {
SonarQubeMonitor.class,
EsMonitor.class,
PluginsMonitor.class,
- JvmPropertiesMonitor.class,
+ JvmPropsMonitor.class,
DatabaseMonitor.class,
+ EsStateMonitor.class,
+ CeStateMonitor.class,
+ CeTasksMonitor.class,
+ CeDatabaseMonitor.class,
MigrateDbAction.class,
LogsAction.class,
ChangeLogLevelAction.class,
diff --git a/server/sonar-server/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplConcurrentTest.java b/server/sonar-server/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplConcurrentTest.java
index edaaf9cd3f8..63c39f6d995 100644
--- a/server/sonar-server/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplConcurrentTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/ce/monitoring/CEQueueStatusImplConcurrentTest.java
@@ -28,9 +28,11 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import org.junit.After;
import org.junit.Test;
+import org.sonar.db.DbClient;
import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
public class CEQueueStatusImplConcurrentTest {
private ExecutorService executorService = Executors.newFixedThreadPool(10, new ThreadFactory() {
@@ -41,7 +43,7 @@ public class CEQueueStatusImplConcurrentTest {
return new Thread(r, CEQueueStatusImplConcurrentTest.class.getSimpleName() + cnt++);
}
});
- private CEQueueStatusImpl underTest = new CEQueueStatusImpl();
+ private CEQueueStatusImpl underTest = new CEQueueStatusImpl(mock(DbClient.class));
@After
public void tearDown() throws Exception {
@@ -50,17 +52,12 @@ public class CEQueueStatusImplConcurrentTest {
@Test
public void test_concurrent_modifications_in_any_order() throws InterruptedException {
- long initialPendingCount = 9963L;
- underTest.initPendingCount(initialPendingCount);
-
for (Runnable runnable : buildShuffleCallsToUnderTest()) {
executorService.submit(runnable);
}
executorService.awaitTermination(1, TimeUnit.SECONDS);
- assertThat(underTest.getReceivedCount()).isEqualTo(100);
- assertThat(underTest.getPendingCount()).isEqualTo(initialPendingCount + 2);
assertThat(underTest.getInProgressCount()).isEqualTo(1);
assertThat(underTest.getErrorCount()).isEqualTo(17);
assertThat(underTest.getSuccessCount()).isEqualTo(80);
@@ -69,9 +66,6 @@ public class CEQueueStatusImplConcurrentTest {
private List buildShuffleCallsToUnderTest() {
List res = new ArrayList<>();
- for (int i = 0; i < 100; i++) {
- res.add(new AddReceivedRunnable());
- }
for (int i = 0; i < 98; i++) {
res.add(new AddInProgressRunnable());
}
@@ -85,13 +79,6 @@ public class CEQueueStatusImplConcurrentTest {
return res;
}
- private class AddReceivedRunnable implements Runnable {
- @Override
- public void run() {
- underTest.addReceived();
- }
- }
-
private class AddInProgressRunnable implements Runnable {
@Override
public void run() {
diff --git a/server/sonar-server/src/test/java/org/sonar/ce/queue/CeQueueImplTest.java b/server/sonar-server/src/test/java/org/sonar/ce/queue/CeQueueImplTest.java
index d18f19edac8..e069e6c296b 100644
--- a/server/sonar-server/src/test/java/org/sonar/ce/queue/CeQueueImplTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/ce/queue/CeQueueImplTest.java
@@ -22,14 +22,11 @@ package org.sonar.ce.queue;
import com.google.common.base.Optional;
import java.util.List;
import javax.annotation.Nullable;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.internal.TestSystem2;
-import org.sonar.ce.monitoring.CEQueueStatus;
-import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
import org.sonar.core.util.UuidFactory;
import org.sonar.core.util.UuidFactoryImpl;
import org.sonar.db.DbSession;
@@ -45,7 +42,6 @@ import static org.hamcrest.Matchers.startsWith;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
public class CeQueueImplTest {
@@ -59,14 +55,8 @@ public class CeQueueImplTest {
DbSession session = dbTester.getSession();
UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE;
- CEQueueStatus queueStatus = new CEQueueStatusImpl();
CeQueueListener listener = mock(CeQueueListener.class);
- CeQueue underTest = new CeQueueImpl(dbTester.getDbClient(), uuidFactory, queueStatus, new CeQueueListener[] {listener});
-
- @Before
- public void setUp() throws Exception {
- queueStatus.initPendingCount(0);
- }
+ CeQueue underTest = new CeQueueImpl(dbTester.getDbClient(), uuidFactory, new CeQueueListener[] {listener});
@Test
public void submit_returns_task_populated_from_CeTaskSubmit_and_creates_CeQueue_row() {
@@ -77,17 +67,6 @@ public class CeQueueImplTest {
verifyCeQueueDtoForTaskSubmit(taskSubmit);
}
- @Test
- public void submit_increments_receivedCount_of_QueueStatus() {
- underTest.submit(createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob"));
-
- assertThat(queueStatus.getReceivedCount()).isEqualTo(1L);
-
- underTest.submit(createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_2", "rob"));
-
- assertThat(queueStatus.getReceivedCount()).isEqualTo(2L);
- }
-
@Test
public void submit_populates_component_name_and_key_of_CeTask_if_component_exists() {
ComponentDto componentDto = insertComponent(newComponentDto("PROJECT_1"));
@@ -144,18 +123,6 @@ public class CeQueueImplTest {
verifyCeTask(taskSubmit2, tasks.get(1), null);
}
- @Test
- public void massSubmit_increments_receivedCount_of_QueueStatus() {
- underTest.massSubmit(asList(createTaskSubmit("type 1"), createTaskSubmit("type 2")));
-
- assertThat(queueStatus.getReceivedCount()).isEqualTo(2L);
-
- underTest.massSubmit(asList(createTaskSubmit("a"), createTaskSubmit("a"), createTaskSubmit("b")));
-
- assertThat(queueStatus.getReceivedCount()).isEqualTo(5L);
- }
-
-
@Test
public void cancel_pending() throws Exception {
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
@@ -259,12 +226,6 @@ public class CeQueueImplTest {
return submission.build();
}
- private CeTaskResult newTaskResult(Long snapshotId) {
- CeTaskResult taskResult = mock(CeTaskResult.class);
- when(taskResult.getSnapshotId()).thenReturn(snapshotId);
- return taskResult;
- }
-
private ComponentDto insertComponent(ComponentDto componentDto) {
dbTester.getDbClient().componentDao().insert(session, componentDto);
session.commit();
diff --git a/server/sonar-server/src/test/java/org/sonar/server/app/ProcessCommandWrapperImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/app/ProcessCommandWrapperImplTest.java
index 8a394785681..e819ec37398 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/app/ProcessCommandWrapperImplTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/app/ProcessCommandWrapperImplTest.java
@@ -43,22 +43,22 @@ public class ProcessCommandWrapperImplTest {
private Settings settings = new Settings();
@Test
- public void requestSQRestart_throws_IAE_if_process_sharedDir_property_not_set() throws Exception {
+ public void requestSQRestart_throws_IAE_if_process_index_property_not_set() throws Exception {
ProcessCommandWrapperImpl processCommandWrapper = new ProcessCommandWrapperImpl(settings);
expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("Property process.sharedDir is not set");
+ expectedException.expectMessage("Property process.index is not set");
processCommandWrapper.requestSQRestart();
}
@Test
- public void requestSQRestart_throws_IAE_if_process_index_property_not_set() throws Exception {
- settings.setProperty(PROPERTY_SHARED_PATH, temp.newFolder().getAbsolutePath());
+ public void requestSQRestart_throws_IAE_if_process_shared_path_property_not_set() throws Exception {
+ settings.setProperty(PROPERTY_PROCESS_INDEX, 1);
ProcessCommandWrapperImpl processCommandWrapper = new ProcessCommandWrapperImpl(settings);
expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("Property process.index is not set");
+ expectedException.expectMessage("Property process.sharedDir is not set");
processCommandWrapper.requestSQRestart();
}
@@ -79,6 +79,7 @@ public class ProcessCommandWrapperImplTest {
@Test
public void notifyOperational_throws_IAE_if_process_sharedDir_property_not_set() throws Exception {
+ settings.setProperty(PROPERTY_PROCESS_INDEX, 1);
ProcessCommandWrapperImpl processCommandWrapper = new ProcessCommandWrapperImpl(settings);
expectedException.expect(IllegalArgumentException.class);
@@ -89,7 +90,6 @@ public class ProcessCommandWrapperImplTest {
@Test
public void notifyOperational_throws_IAE_if_process_index_property_not_set() throws Exception {
- settings.setProperty(PROPERTY_SHARED_PATH, temp.newFolder().getAbsolutePath());
ProcessCommandWrapperImpl processCommandWrapper = new ProcessCommandWrapperImpl(settings);
expectedException.expect(IllegalArgumentException.class);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CEQueueStatusImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CEQueueStatusImplTest.java
index b1d82c150b4..733383fc65c 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CEQueueStatusImplTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CEQueueStatusImplTest.java
@@ -23,23 +23,29 @@ import java.util.Random;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
+import org.mockito.Mockito;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.ce.CeQueueDto;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class CEQueueStatusImplTest {
private static final int SOME_RANDOM_MAX = 96535;
private static final int SOME_PROCESSING_TIME = 8723;
- private static final long INITIAL_PENDING_COUNT = 996L;
@Rule
public ExpectedException expectedException = ExpectedException.none();
- private CEQueueStatusImpl underTest = new CEQueueStatusImpl();
+ DbClient dbClient = mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS);
+ private CEQueueStatusImpl underTest = new CEQueueStatusImpl(dbClient);
@Test
public void verify_just_created_instance_metrics() {
- assertThat(underTest.getReceivedCount()).isEqualTo(0);
- assertThat(underTest.getPendingCount()).isEqualTo(0);
assertThat(underTest.getInProgressCount()).isEqualTo(0);
assertThat(underTest.getErrorCount()).isEqualTo(0);
assertThat(underTest.getSuccessCount()).isEqualTo(0);
@@ -47,117 +53,9 @@ public class CEQueueStatusImplTest {
}
@Test
- public void initPendingCount_sets_value_of_pendingCount() {
- underTest.initPendingCount(10);
-
- assertThat(underTest.getPendingCount()).isEqualTo(10);
- }
-
- @Test
- public void initPendingCount_throws_ISE_if_called_twice() {
- expectedException.expect(IllegalStateException.class);
- expectedException.expectMessage("Method initPendingCount must be used before any other method and can not be called twice");
-
- underTest.initPendingCount(10);
- underTest.initPendingCount(10);
- }
-
- @Test
- public void addReceived_throws_ISE_if_called_before_initPendingCount() {
- expectedException.expect(IllegalStateException.class);
- expectedException.expectMessage("Method initPendingCount must be used before addReceived can be called");
-
- underTest.addReceived();
- }
-
- @Test
- public void addReceived_sets_received_to_1_and_pending_counts_to_initial_value_plus_1() {
- underTest.initPendingCount(INITIAL_PENDING_COUNT);
-
- underTest.addReceived();
-
- assertThat(underTest.getReceivedCount()).isEqualTo(1);
- assertThat(underTest.getPendingCount()).isEqualTo(INITIAL_PENDING_COUNT + 1);
- }
-
- @Test
- public void addReceived_any_number_of_call_adds_1_per_call() {
- underTest.initPendingCount(INITIAL_PENDING_COUNT);
-
- int calls = new Random().nextInt(SOME_RANDOM_MAX);
- for (int i = 0; i < calls; i++) {
- underTest.addReceived();
- }
-
- assertThat(underTest.getReceivedCount()).isEqualTo(calls);
- assertThat(underTest.getPendingCount()).isEqualTo(INITIAL_PENDING_COUNT + calls);
- }
-
- @Test
- public void addReceived_with_argument_throws_IAE_if_parameter_is_0() {
- underTest.initPendingCount(INITIAL_PENDING_COUNT);
-
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("numberOfReceived must be > 0");
-
- underTest.addReceived(0);
- }
-
- @Test
- public void addReceived_with_argument_throws_IAE_if_parameter_less_than_0() {
- underTest.initPendingCount(INITIAL_PENDING_COUNT);
-
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("numberOfReceived must be > 0");
-
- underTest.addReceived(-1 * (new Random().nextInt(SOME_RANDOM_MAX)));
- }
-
- @Test
- public void addReceived_with_argument_sets_received_to_value_and_pending_counts_to_initial_value_plus_value() {
- long value = 123;
- underTest.initPendingCount(INITIAL_PENDING_COUNT);
-
- underTest.addReceived(value);
-
- assertThat(underTest.getReceivedCount()).isEqualTo(value);
- assertThat(underTest.getPendingCount()).isEqualTo(INITIAL_PENDING_COUNT + value);
- }
-
- @Test
- public void addReceived_with_argument_any_number_of_call_adds_some_number_per_call() {
- underTest.initPendingCount(INITIAL_PENDING_COUNT);
-
- Random random = new Random();
- int calls = random.nextInt(SOME_RANDOM_MAX);
- long added = 0;
- for (int i = 0; i < calls; i++) {
- // adding 1 to random number because value can not be 0
- long numberOfReceived = random.nextInt(SOME_RANDOM_MAX) + 1;
- underTest.addReceived(numberOfReceived);
- added += numberOfReceived;
- }
-
- assertThat(underTest.getReceivedCount()).isEqualTo(added);
- assertThat(underTest.getPendingCount()).isEqualTo(INITIAL_PENDING_COUNT + added);
- }
-
- @Test
- public void addInProgress_throws_ISE_if_called_before_initPendingCount() {
- expectedException.expect(IllegalStateException.class);
- expectedException.expectMessage("Method initPendingCount must be used before addInProgress can be called");
-
+ public void addInProgress_increases_InProgress() {
underTest.addInProgress();
- }
-
- @Test
- public void addInProgress_increases_InProgress_and_decreases_Pending_by_1_without_check_on_Pending() {
- underTest.initPendingCount(INITIAL_PENDING_COUNT);
- underTest.addInProgress();
-
- assertThat(underTest.getReceivedCount()).isEqualTo(0);
- assertThat(underTest.getPendingCount()).isEqualTo(INITIAL_PENDING_COUNT - 1);
assertThat(underTest.getInProgressCount()).isEqualTo(1);
assertThat(underTest.getErrorCount()).isEqualTo(0);
assertThat(underTest.getSuccessCount()).isEqualTo(0);
@@ -166,15 +64,12 @@ public class CEQueueStatusImplTest {
@Test
public void addInProgress_any_number_of_call_change_by_1_per_call() {
- underTest.initPendingCount(INITIAL_PENDING_COUNT);
-
int calls = new Random().nextInt(SOME_RANDOM_MAX);
for (int i = 0; i < calls; i++) {
underTest.addInProgress();
}
assertThat(underTest.getInProgressCount()).isEqualTo(calls);
- assertThat(underTest.getPendingCount()).isEqualTo(INITIAL_PENDING_COUNT - calls);
assertThat(underTest.getProcessingTime()).isEqualTo(0);
}
@@ -190,8 +85,6 @@ public class CEQueueStatusImplTest {
public void addError_increases_Error_and_decreases_InProgress_by_1_without_check_on_InProgress() {
underTest.addError(SOME_PROCESSING_TIME);
- assertThat(underTest.getReceivedCount()).isEqualTo(0);
- assertThat(underTest.getPendingCount()).isEqualTo(0);
assertThat(underTest.getInProgressCount()).isEqualTo(-1);
assertThat(underTest.getErrorCount()).isEqualTo(1);
assertThat(underTest.getSuccessCount()).isEqualTo(0);
@@ -222,8 +115,6 @@ public class CEQueueStatusImplTest {
public void addSuccess_increases_Error_and_decreases_InProgress_by_1_without_check_on_InProgress() {
underTest.addSuccess(SOME_PROCESSING_TIME);
- assertThat(underTest.getReceivedCount()).isEqualTo(0);
- assertThat(underTest.getPendingCount()).isEqualTo(0);
assertThat(underTest.getInProgressCount()).isEqualTo(-1);
assertThat(underTest.getErrorCount()).isEqualTo(0);
assertThat(underTest.getSuccessCount()).isEqualTo(1);
@@ -241,4 +132,11 @@ public class CEQueueStatusImplTest {
assertThat(underTest.getInProgressCount()).isEqualTo(-calls);
assertThat(underTest.getProcessingTime()).isEqualTo(calls);
}
+
+ @Test
+ public void count_Pending_from_database() {
+ when(dbClient.ceQueueDao().countByStatus(any(DbSession.class), eq(CeQueueDto.Status.PENDING))).thenReturn(42);
+
+ assertThat(underTest.getPendingCount()).isEqualTo(42);
+ }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/ComputeEngineQueueMonitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CeTasksMBeanImplTest.java
similarity index 70%
rename from server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/ComputeEngineQueueMonitorTest.java
rename to server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CeTasksMBeanImplTest.java
index bca30441ecc..9b5bc7becc8 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/ComputeEngineQueueMonitorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CeTasksMBeanImplTest.java
@@ -19,17 +19,19 @@
*/
package org.sonar.server.computation.monitoring;
+import java.lang.management.ManagementFactory;
+import javax.annotation.CheckForNull;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
import org.junit.Test;
import org.sonar.ce.monitoring.CEQueueStatus;
+import org.sonar.process.jmx.CeTasksMBean;
import org.sonar.server.computation.configuration.CeConfiguration;
-import org.sonar.ce.queue.CeQueueImpl;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
-import static org.mockito.Mockito.mock;
-public class ComputeEngineQueueMonitorTest {
- private static final long RECEIVED_COUNT = 30;
+public class CeTasksMBeanImplTest {
private static final long PENDING_COUNT = 2;
private static final long IN_PROGRESS_COUNT = 5;
private static final long ERROR_COUNT = 10;
@@ -37,28 +39,21 @@ public class ComputeEngineQueueMonitorTest {
private static final long PROCESSING_TIME = 987;
private static final int WORKER_COUNT = 56;
- private ComputeEngineQueueMonitor underTest = new ComputeEngineQueueMonitor(new DumbCEQueueStatus(), mock(CeQueueImpl.class), new DumbCeConfiguration());
+ private CeTasksMBeanImpl underTest = new CeTasksMBeanImpl(new DumbCEQueueStatus(), new DumbCeConfiguration());
@Test
- public void name_is_ComputeEngine() {
- assertThat(underTest.name()).isEqualTo("ComputeEngine");
- }
+ public void register_and_unregister() throws Exception {
+ assertThat(getMBean()).isNull();
- @Test
- public void attributes_has_entry_for_each_get_method() {
- assertThat(underTest.attributes()).containsOnly(
- entry("Received", RECEIVED_COUNT),
- entry("Pending", PENDING_COUNT),
- entry("In progress", IN_PROGRESS_COUNT),
- entry("Successfully processed", SUCCESS_COUNT),
- entry("Processed with error", ERROR_COUNT),
- entry("Processing time", PROCESSING_TIME),
- entry("Worker count", WORKER_COUNT));
+ underTest.start();
+ assertThat(getMBean()).isNotNull();
+
+ underTest.stop();
+ assertThat(getMBean()).isNull();
}
@Test
public void get_methods_delegate_to_the_CEQueueStatus_instance() {
- assertThat(underTest.getReceivedCount()).isEqualTo(RECEIVED_COUNT);
assertThat(underTest.getPendingCount()).isEqualTo(PENDING_COUNT);
assertThat(underTest.getInProgressCount()).isEqualTo(IN_PROGRESS_COUNT);
assertThat(underTest.getErrorCount()).isEqualTo(ERROR_COUNT);
@@ -77,26 +72,6 @@ public class ComputeEngineQueueMonitorTest {
*/
private static class DumbCEQueueStatus implements CEQueueStatus {
- @Override
- public long addReceived() {
- return methodNotImplemented();
- }
-
- @Override
- public long addReceived(long numberOfReceived) {
- return methodNotImplemented();
- }
-
- @Override
- public long getReceivedCount() {
- return RECEIVED_COUNT;
- }
-
- @Override
- public long initPendingCount(long initialPendingCount) {
- return methodNotImplemented();
- }
-
@Override
public long getPendingCount() {
return PENDING_COUNT;
@@ -153,4 +128,13 @@ public class ComputeEngineQueueMonitorTest {
throw new UnsupportedOperationException("getQueuePollingDelay is not implemented");
}
}
+
+ @CheckForNull
+ private ObjectInstance getMBean() throws Exception {
+ try {
+ return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(CeTasksMBean.OBJECT_NAME));
+ } catch (InstanceNotFoundException e) {
+ return null;
+ }
+ }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/queue/CeQueueInitializerTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/queue/CeQueueInitializerTest.java
index 41f42da6364..473ebc092ed 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/queue/CeQueueInitializerTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/queue/CeQueueInitializerTest.java
@@ -19,64 +19,31 @@
*/
package org.sonar.server.computation.queue;
-import java.io.File;
import java.io.IOException;
import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
import org.mockito.InOrder;
import org.mockito.Mockito;
import org.sonar.api.platform.Server;
import org.sonar.api.utils.System2;
import org.sonar.db.DbSession;
import org.sonar.db.DbTester;
-import org.sonar.db.ce.CeQueueDto;
-import org.sonar.db.ce.CeTaskTypes;
-import org.sonar.ce.monitoring.CEQueueStatus;
-import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
-import org.sonar.ce.queue.report.ReportFiles;
import org.sonar.server.computation.taskprocessor.CeProcessingScheduler;
-import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
public class CeQueueInitializerTest {
@Rule
public DbTester dbTester = DbTester.create(System2.INSTANCE);
- @Rule
- public TemporaryFolder tempFolder = new TemporaryFolder();
-
Server server = mock(Server.class);
- ReportFiles reportFiles = mock(ReportFiles.class, Mockito.RETURNS_DEEP_STUBS);
- CEQueueStatus queueStatus = new CEQueueStatusImpl();
CeQueueCleaner cleaner = mock(CeQueueCleaner.class);
CeProcessingScheduler scheduler = mock(CeProcessingScheduler.class);
- CeQueueInitializer underTest = new CeQueueInitializer(dbTester.getDbClient(), queueStatus, cleaner, scheduler);
-
- @Test
- public void init_jmx_counters() throws IOException {
- insertInQueue("TASK_1", CeQueueDto.Status.PENDING);
- insertInQueue("TASK_2", CeQueueDto.Status.PENDING);
- // this in-progress task is going to be moved to PENDING
- insertInQueue("TASK_3", CeQueueDto.Status.IN_PROGRESS);
-
- underTest.onServerStart(server);
-
- assertThat(queueStatus.getPendingCount()).isEqualTo(3);
- }
-
- @Test
- public void init_jmx_counters_when_queue_is_empty() {
- underTest.onServerStart(server);
-
- assertThat(queueStatus.getPendingCount()).isEqualTo(0);
- }
+ CeQueueInitializer underTest = new CeQueueInitializer(dbTester.getDbClient(), cleaner, scheduler);
@Test
public void clean_queue_then_start_scheduler_of_workers() throws IOException {
@@ -100,25 +67,4 @@ public class CeQueueInitializerTest {
verifyZeroInteractions(cleaner, scheduler);
}
-
- private void insertInQueue(String taskUuid, CeQueueDto.Status status) throws IOException {
- insertInQueue(taskUuid, status, true);
- }
-
- private CeQueueDto insertInQueue(String taskUuid, CeQueueDto.Status status, boolean createFile) throws IOException {
- CeQueueDto queueDto = new CeQueueDto();
- queueDto.setTaskType(CeTaskTypes.REPORT);
- queueDto.setComponentUuid("PROJECT_1");
- queueDto.setUuid(taskUuid);
- queueDto.setStatus(status);
- dbTester.getDbClient().ceQueueDao().insert(dbTester.getSession(), queueDto);
- dbTester.getSession().commit();
-
- File file = tempFolder.newFile();
- when(reportFiles.fileForUuid(taskUuid)).thenReturn(file);
- if (!createFile) {
- file.delete();
- }
- return queueDto;
- }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/queue/InternalCeQueueImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/queue/InternalCeQueueImplTest.java
index 8220ef23961..aeedba846ce 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/queue/InternalCeQueueImplTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/queue/InternalCeQueueImplTest.java
@@ -22,14 +22,12 @@ package org.sonar.server.computation.queue;
import com.google.common.base.Optional;
import java.util.List;
import javax.annotation.Nullable;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.utils.System2;
import org.sonar.api.utils.internal.TestSystem2;
import org.sonar.ce.monitoring.CEQueueStatus;
-import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
import org.sonar.ce.queue.CeQueueListener;
import org.sonar.ce.queue.CeTask;
import org.sonar.ce.queue.CeTaskResult;
@@ -42,6 +40,7 @@ import org.sonar.db.ce.CeActivityDto;
import org.sonar.db.ce.CeQueueDto;
import org.sonar.db.ce.CeTaskTypes;
import org.sonar.db.component.ComponentDto;
+import org.sonar.server.computation.monitoring.CEQueueStatusImpl;
import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
@@ -66,15 +65,10 @@ public class InternalCeQueueImplTest {
DbSession session = dbTester.getSession();
UuidFactory uuidFactory = UuidFactoryImpl.INSTANCE;
- CEQueueStatus queueStatus = new CEQueueStatusImpl();
+ CEQueueStatus queueStatus = new CEQueueStatusImpl(dbTester.getDbClient());
CeQueueListener listener = mock(CeQueueListener.class);
InternalCeQueue underTest = new InternalCeQueueImpl(system2, dbTester.getDbClient(), uuidFactory, queueStatus, new CeQueueListener[] {listener});
- @Before
- public void setUp() throws Exception {
- queueStatus.initPendingCount(0);
- }
-
@Test
public void submit_returns_task_populated_from_CeTaskSubmit_and_creates_CeQueue_row() {
CeTaskSubmit taskSubmit = createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob");
@@ -84,17 +78,6 @@ public class InternalCeQueueImplTest {
verifyCeQueueDtoForTaskSubmit(taskSubmit);
}
- @Test
- public void submit_increments_receivedCount_of_QueueStatus() {
- underTest.submit(createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_1", "rob"));
-
- assertThat(queueStatus.getReceivedCount()).isEqualTo(1L);
-
- underTest.submit(createTaskSubmit(CeTaskTypes.REPORT, "PROJECT_2", "rob"));
-
- assertThat(queueStatus.getReceivedCount()).isEqualTo(2L);
- }
-
@Test
public void submit_populates_component_name_and_key_of_CeTask_if_component_exists() {
ComponentDto componentDto = insertComponent(newComponentDto("PROJECT_1"));
@@ -151,17 +134,6 @@ public class InternalCeQueueImplTest {
verifyCeTask(taskSubmit2, tasks.get(1), null);
}
- @Test
- public void massSubmit_increments_receivedCount_of_QueueStatus() {
- underTest.massSubmit(asList(createTaskSubmit("type 1"), createTaskSubmit("type 2")));
-
- assertThat(queueStatus.getReceivedCount()).isEqualTo(2L);
-
- underTest.massSubmit(asList(createTaskSubmit("a"), createTaskSubmit("a"), createTaskSubmit("b")));
-
- assertThat(queueStatus.getReceivedCount()).isEqualTo(5L);
- }
-
@Test
public void test_remove() {
CeTask task = submit(CeTaskTypes.REPORT, "PROJECT_1");
diff --git a/server/sonar-server/src/test/java/org/sonar/server/es/EsServerHolder.java b/server/sonar-server/src/test/java/org/sonar/server/es/EsServerHolder.java
index 41a5c8b891c..be6fb6a1259 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/es/EsServerHolder.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/es/EsServerHolder.java
@@ -19,20 +19,20 @@
*/
package org.sonar.server.es;
+import java.io.File;
+import java.util.Properties;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.sonar.process.LoopbackAddress;
import org.sonar.process.NetworkUtils;
+import org.sonar.process.ProcessEntryPoint;
import org.sonar.process.ProcessProperties;
import org.sonar.process.Props;
import org.sonar.search.SearchServer;
import org.sonar.test.TestUtils;
-import java.io.File;
-import java.util.Properties;
-
public class EsServerHolder {
private static EsServerHolder HOLDER = null;
@@ -114,6 +114,7 @@ public class EsServerHolder {
properties.setProperty(ProcessProperties.SEARCH_PORT, String.valueOf(port));
properties.setProperty(ProcessProperties.SEARCH_HOST, hostName);
properties.setProperty(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath());
+ properties.setProperty(ProcessEntryPoint.PROPERTY_SHARED_PATH, homeDir.getAbsolutePath());
SearchServer server = new SearchServer(new Props(properties));
server.start();
HOLDER = new EsServerHolder(server, clusterName, nodeName, port, hostName, homeDir);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/BaseMonitorMBeanTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/BaseMonitorMBeanTest.java
index 38adaa34662..514bb7fb7c6 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/BaseMonitorMBeanTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/BaseMonitorMBeanTest.java
@@ -19,12 +19,12 @@
*/
package org.sonar.server.platform.monitoring;
-import org.junit.Test;
-
+import java.lang.management.ManagementFactory;
import javax.annotation.CheckForNull;
import javax.management.InstanceNotFoundException;
import javax.management.ObjectInstance;
-import java.lang.management.ManagementFactory;
+import javax.management.ObjectName;
+import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
@@ -52,7 +52,7 @@ public class BaseMonitorMBeanTest {
@CheckForNull
private ObjectInstance getMBean() throws Exception {
try {
- return ManagementFactory.getPlatformMBeanServer().getObjectInstance(underTest.objectName());
+ return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(underTest.objectName()));
} catch (InstanceNotFoundException e) {
return null;
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeDatabaseMonitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeDatabaseMonitorTest.java
new file mode 100644
index 00000000000..4c2ce9ed035
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeDatabaseMonitorTest.java
@@ -0,0 +1,53 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import java.util.LinkedHashMap;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.sonar.process.ProcessId;
+import org.sonar.process.jmx.CeDatabaseMBean;
+import org.sonar.process.jmx.JmxConnectionFactory;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class CeDatabaseMonitorTest {
+
+ JmxConnectionFactory jmxConnectionFactory = mock(JmxConnectionFactory.class, Mockito.RETURNS_DEEP_STUBS);
+ CeDatabaseMonitor underTest = new CeDatabaseMonitor(jmxConnectionFactory);
+
+ @Test
+ public void testName() {
+ assertThat(underTest.name()).isNotEmpty();
+ }
+
+ @Test
+ public void testAttributes() {
+ CeDatabaseMBean mbean = mock(CeDatabaseMBean.class, Mockito.RETURNS_DEFAULTS);
+
+ when(jmxConnectionFactory.create(ProcessId.COMPUTE_ENGINE).getMBean(CeDatabaseMBean.OBJECT_NAME, CeDatabaseMBean.class))
+ .thenReturn(mbean);
+ LinkedHashMap attributes = underTest.attributes();
+ assertThat(attributes).containsKeys("Pool Initial Size", "Pool Active Connections");
+ assertThat(attributes).hasSize(9);
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeStateMonitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeStateMonitorTest.java
new file mode 100644
index 00000000000..5db51a693fa
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeStateMonitorTest.java
@@ -0,0 +1,53 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import com.google.common.collect.ImmutableSortedMap;
+import java.util.LinkedHashMap;
+import org.assertj.core.data.MapEntry;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.sonar.process.ProcessId;
+import org.sonar.process.jmx.JmxConnectionFactory;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class CeStateMonitorTest {
+
+ JmxConnectionFactory jmxConnectionFactory = mock(JmxConnectionFactory.class, Mockito.RETURNS_DEEP_STUBS);
+ CeStateMonitor underTest = new CeStateMonitor(jmxConnectionFactory);
+
+ @Test
+ public void testName() {
+ assertThat(underTest.name()).isNotEmpty();
+ }
+
+ @Test
+ public void testAttributes() {
+ when(jmxConnectionFactory.create(ProcessId.COMPUTE_ENGINE).getSystemState()).thenReturn(ImmutableSortedMap.of(
+ "foo", "foo_val", "bar", "bar_val"));
+ LinkedHashMap attributes = underTest.attributes();
+ assertThat(attributes).containsExactly(
+ MapEntry.entry("bar", "bar_val"),
+ MapEntry.entry("foo", "foo_val"));
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeTasksMonitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeTasksMonitorTest.java
new file mode 100644
index 00000000000..cf1902601ae
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeTasksMonitorTest.java
@@ -0,0 +1,53 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import java.util.LinkedHashMap;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.sonar.process.ProcessId;
+import org.sonar.process.jmx.CeTasksMBean;
+import org.sonar.process.jmx.JmxConnectionFactory;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class CeTasksMonitorTest {
+
+ JmxConnectionFactory jmxConnectionFactory = mock(JmxConnectionFactory.class, Mockito.RETURNS_DEEP_STUBS);
+ CeTasksMonitor underTest = new CeTasksMonitor(jmxConnectionFactory);
+
+ @Test
+ public void testName() {
+ assertThat(underTest.name()).isNotEmpty();
+ }
+
+ @Test
+ public void testAttributes() {
+ CeTasksMBean mbean = mock(CeTasksMBean.class, Mockito.RETURNS_DEFAULTS);
+
+ when(jmxConnectionFactory.create(ProcessId.COMPUTE_ENGINE).getMBean(CeTasksMBean.OBJECT_NAME, CeTasksMBean.class))
+ .thenReturn(mbean);
+ LinkedHashMap attributes = underTest.attributes();
+ assertThat(attributes).containsKeys("Pending");
+ assertThat(attributes).hasSize(6);
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/DatabaseMonitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/DatabaseMonitorTest.java
index 82023198119..1e7cb5eccc5 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/DatabaseMonitorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/DatabaseMonitorTest.java
@@ -42,6 +42,11 @@ public class DatabaseMonitorTest {
underTest = new DatabaseMonitor(dbVersion, dbTester.getDbClient());
}
+ @Test
+ public void name_is_not_empty() {
+ assertThat(underTest.name()).isNotEmpty();
+ }
+
@Test
public void db_info() {
LinkedHashMap attributes = underTest.attributes();
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/EsMonitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/EsMonitorTest.java
index 76f4b1dd1a3..0716a6415a8 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/EsMonitorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/EsMonitorTest.java
@@ -22,58 +22,69 @@ package org.sonar.server.platform.monitoring;
import java.util.LinkedHashMap;
import java.util.Map;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
+import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
+import org.mockito.Mockito;
import org.sonar.api.config.Settings;
+import org.sonar.process.ProcessId;
+import org.sonar.process.jmx.EsSettingsMBean;
+import org.sonar.process.jmx.JmxConnectionFactory;
import org.sonar.server.es.EsTester;
import org.sonar.server.es.NewIndex;
import org.sonar.server.issue.index.IssueIndexDefinition;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class EsMonitorTest {
@ClassRule
public static EsTester esTester = new EsTester().addDefinitions(new IssueIndexDefinition(new Settings()));
+ JmxConnectionFactory jmxConnectionFactory = mock(JmxConnectionFactory.class, Mockito.RETURNS_DEEP_STUBS);
+ EsSettingsMBean settingsMBean = mock(EsSettingsMBean.class);
+ EsMonitor underTest = new EsMonitor(jmxConnectionFactory, esTester.client());
+
+ @Before
+ public void setUp() throws Exception {
+ when(jmxConnectionFactory.create(ProcessId.ELASTICSEARCH).getMBean(EsSettingsMBean.OBJECT_NAME, EsSettingsMBean.class)).thenReturn(settingsMBean);
+ }
+
@Test
public void name() {
- EsMonitor monitor = new EsMonitor(esTester.client());
- assertThat(monitor.name()).isEqualTo("ElasticSearch");
+ assertThat(underTest.name()).isEqualTo("Elasticsearch");
}
-
@Test
public void cluster_attributes() {
- EsMonitor monitor = new EsMonitor(esTester.client());
- LinkedHashMap attributes = monitor.attributes();
- assertThat(monitor.getState()).isEqualTo(ClusterHealthStatus.GREEN.name());
+ LinkedHashMap attributes = underTest.attributes();
+ assertThat(underTest.getState()).isEqualTo(ClusterHealthStatus.GREEN.name());
assertThat(attributes.get("State")).isEqualTo(ClusterHealthStatus.GREEN);
assertThat(attributes.get("Number of Nodes")).isEqualTo(1);
}
@Test
public void node_attributes() {
- EsMonitor monitor = new EsMonitor(esTester.client());
- LinkedHashMap attributes = monitor.attributes();
- Map nodesAttributes = (Map)attributes.get("Nodes");
+ LinkedHashMap attributes = underTest.attributes();
+ Map nodesAttributes = (Map) attributes.get("Nodes");
// one node
assertThat(nodesAttributes).hasSize(1);
- Map nodeAttributes = (Map)nodesAttributes.values().iterator().next();
+ Map nodeAttributes = (Map) nodesAttributes.values().iterator().next();
assertThat(nodeAttributes.get("Type")).isEqualTo("Master");
assertThat(nodeAttributes.get("Store Size")).isNotNull();
}
@Test
public void index_attributes() {
- EsMonitor monitor = new EsMonitor(esTester.client());
- LinkedHashMap attributes = monitor.attributes();
- Map indicesAttributes = (Map)attributes.get("Indices");
+ LinkedHashMap attributes = underTest.attributes();
+ Map indicesAttributes = (Map) attributes.get("Indices");
// one index "issues"
assertThat(indicesAttributes).hasSize(1);
- Map indexAttributes = (Map)indicesAttributes.values().iterator().next();
+ Map indexAttributes = (Map) indicesAttributes.values().iterator().next();
assertThat(indexAttributes.get("Docs")).isEqualTo(0L);
assertThat(indexAttributes.get("Shards")).isEqualTo(NewIndex.DEFAULT_NUMBER_OF_SHARDS);
assertThat(indexAttributes.get("Store Size")).isNotNull();
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/EsStateMonitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/EsStateMonitorTest.java
new file mode 100644
index 00000000000..e06f5c9c111
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/EsStateMonitorTest.java
@@ -0,0 +1,52 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import com.google.common.collect.ImmutableSortedMap;
+import java.util.LinkedHashMap;
+import org.assertj.core.data.MapEntry;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.sonar.process.ProcessId;
+import org.sonar.process.jmx.JmxConnectionFactory;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class EsStateMonitorTest {
+ JmxConnectionFactory jmxConnectionFactory = mock(JmxConnectionFactory.class, Mockito.RETURNS_DEEP_STUBS);
+ EsStateMonitor underTest = new EsStateMonitor(jmxConnectionFactory);
+
+ @Test
+ public void testName() {
+ assertThat(underTest.name()).isNotEmpty();
+ }
+
+ @Test
+ public void testAttributes() {
+ when(jmxConnectionFactory.create(ProcessId.ELASTICSEARCH).getSystemState()).thenReturn(ImmutableSortedMap.of(
+ "foo", "foo_val", "bar", "bar_val"));
+ LinkedHashMap attributes = underTest.attributes();
+ assertThat(attributes).containsExactly(
+ MapEntry.entry("bar", "bar_val"),
+ MapEntry.entry("foo", "foo_val"));
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JmxConnectionFactoryProviderTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JmxConnectionFactoryProviderTest.java
new file mode 100644
index 00000000000..5a461bc21c3
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JmxConnectionFactoryProviderTest.java
@@ -0,0 +1,56 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2016 SonarSource SA
+ * mailto:contact AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.config.Settings;
+import org.sonar.process.ProcessEntryPoint;
+import org.sonar.process.jmx.JmxConnectionFactory;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class JmxConnectionFactoryProviderTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ Settings settings = new Settings();
+ JmxConnectorProvider underTest = new JmxConnectorProvider();
+
+ @Test
+ public void provide_JmxConnector() {
+ settings.setProperty(ProcessEntryPoint.PROPERTY_SHARED_PATH, "path/");
+ JmxConnectionFactory connector = underTest.provide(settings);
+
+ assertThat(connector).isNotNull();
+ // cache
+ assertThat(underTest.provide(settings)).isSameAs(connector);
+ }
+
+ @Test
+ public void throw_IAE_if_ipc_shared_path_is_not_set() {
+ expectedException.expect(IllegalArgumentException.class);
+ expectedException.expectMessage("Property process.sharedDir is not set");
+
+ underTest.provide(settings);
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JvmPropertiesMonitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JvmPropsMonitorTest.java
similarity index 86%
rename from server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JvmPropertiesMonitorTest.java
rename to server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JvmPropsMonitorTest.java
index e1692321e98..48ce163e151 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JvmPropertiesMonitorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JvmPropsMonitorTest.java
@@ -19,17 +19,22 @@
*/
package org.sonar.server.platform.monitoring;
-import org.junit.Test;
-
import java.util.LinkedHashMap;
+import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
-public class JvmPropertiesMonitorTest {
+public class JvmPropsMonitorTest {
+
+ JvmPropsMonitor underTest = new JvmPropsMonitor();
+
+ @Test
+ public void name_is_not_empty() {
+ assertThat(underTest.name()).isNotEmpty();
+ }
@Test
public void attributes() {
- JvmPropertiesMonitor underTest = new JvmPropertiesMonitor();
LinkedHashMap attributes = underTest.attributes();
assertThat(attributes).containsKeys("java.vm.vendor", "os.name");
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SonarQubeMonitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SonarQubeMonitorTest.java
index 16889862087..9c9f91999d9 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SonarQubeMonitorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SonarQubeMonitorTest.java
@@ -51,6 +51,11 @@ public class SonarQubeMonitorTest {
when(serverLogging.getRootLoggerLevel()).thenReturn(LoggerLevel.DEBUG);
}
+ @Test
+ public void name_is_not_empty() {
+ assertThat(new SonarQubeMonitor(settings, new SecurityRealmFactory(settings), server, serverLogging).name()).isNotEmpty();
+ }
+
@Test
public void getServerId() {
when(server.getStartedAt()).thenReturn(DateUtils.parseDate("2015-01-01"));
diff --git a/server/sonar-web/src/main/js/apps/system/main.js b/server/sonar-web/src/main/js/apps/system/main.js
index 0fbabea94bd..ea003bb7de6 100644
--- a/server/sonar-web/src/main/js/apps/system/main.js
+++ b/server/sonar-web/src/main/js/apps/system/main.js
@@ -24,8 +24,8 @@ import Section from './section';
import { translate } from '../../helpers/l10n';
import RestartModal from '../../components/RestartModal';
-const SECTIONS_ORDER = ['SonarQube', 'Database', 'Plugins', 'System', 'ElasticSearch', 'JvmProperties',
- 'ComputeEngine'];
+const SECTIONS_ORDER = ['SonarQube', 'Database', 'Plugins', 'System', 'Elasticsearch State', 'Elasticsearch',
+ 'Compute Engine Tasks', 'Compute Engine State', 'Compute Engine Database', 'JvmProperties'];
export default React.createClass({
componentDidMount() {
diff --git a/sonar-application/src/main/java/org/sonar/application/App.java b/sonar-application/src/main/java/org/sonar/application/App.java
index 35e9f491694..de5db3c03e4 100644
--- a/sonar-application/src/main/java/org/sonar/application/App.java
+++ b/sonar-application/src/main/java/org/sonar/application/App.java
@@ -27,26 +27,24 @@ import java.util.Properties;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;
import org.sonar.process.MinimumViableSystem;
+import org.sonar.process.ProcessId;
import org.sonar.process.ProcessProperties;
import org.sonar.process.Props;
import org.sonar.process.Stoppable;
import org.sonar.process.monitor.JavaCommand;
import org.sonar.process.monitor.Monitor;
+import static org.sonar.process.ProcessId.APP;
+
/**
* Entry-point of process that starts and monitors ElasticSearch, the Web Server and the Compute Engine.
*/
public class App implements Stoppable {
- public static final int APP_PROCESS_NUMBER = 0;
- public static final int ES_PROCESS_INDEX = 1;
- public static final int WEBSERVER_PROCESS_INDEX = 2;
- public static final int CESERVER_PROCESS_INDEX = 3;
-
private final Monitor monitor;
public App(AppFileSystem appFileSystem, boolean watchForHardStop) {
- this(Monitor.create(APP_PROCESS_NUMBER, appFileSystem, watchForHardStop));
+ this(Monitor.create(APP.getIpcIndex(), appFileSystem, watchForHardStop));
}
App(Monitor monitor) {
@@ -74,7 +72,7 @@ public class App implements Stoppable {
}
private static JavaCommand createESCommand(Props props, File homeDir) {
- JavaCommand elasticsearch = new JavaCommand("search", ES_PROCESS_INDEX);
+ JavaCommand elasticsearch = new JavaCommand(ProcessId.ELASTICSEARCH);
elasticsearch
.setWorkDir(homeDir)
.addJavaOptions("-Djava.awt.headless=true")
@@ -88,7 +86,7 @@ public class App implements Stoppable {
}
private static JavaCommand createWebServerCommand(Props props, File homeDir) {
- JavaCommand webServer = new JavaCommand("web", WEBSERVER_PROCESS_INDEX)
+ JavaCommand webServer = new JavaCommand(ProcessId.WEB_SERVER)
.setWorkDir(homeDir)
.addJavaOptions(ProcessProperties.WEB_ENFORCED_JVM_ARGS)
.addJavaOptions(props.nonNullValue(ProcessProperties.WEB_JAVA_OPTS))
@@ -107,7 +105,7 @@ public class App implements Stoppable {
}
private static JavaCommand createCeServerCommand(Props props, File homeDir) {
- JavaCommand webServer = new JavaCommand("ce", CESERVER_PROCESS_INDEX)
+ JavaCommand webServer = new JavaCommand(ProcessId.COMPUTE_ENGINE)
.setWorkDir(homeDir)
.addJavaOptions(ProcessProperties.CE_ENFORCED_JVM_ARGS)
.addJavaOptions(props.nonNullValue(ProcessProperties.CE_JAVA_OPTS))
diff --git a/sonar-application/src/test/java/org/sonar/application/AppTest.java b/sonar-application/src/test/java/org/sonar/application/AppTest.java
index 70f694c97dc..8150639c865 100644
--- a/sonar-application/src/test/java/org/sonar/application/AppTest.java
+++ b/sonar-application/src/test/java/org/sonar/application/AppTest.java
@@ -28,6 +28,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.ArgumentCaptor;
+import org.sonar.process.ProcessId;
import org.sonar.process.ProcessProperties;
import org.sonar.process.Props;
import org.sonar.process.monitor.JavaCommand;
@@ -52,7 +53,7 @@ public class AppTest {
}
@Test
- public void start_elasticsearch_and_tomcat_by_default() throws Exception {
+ public void start_all_processes_by_default() throws Exception {
Monitor monitor = mock(Monitor.class);
App app = new App(monitor);
Props props = initDefaultProps();
@@ -61,7 +62,7 @@ public class AppTest {
ArgumentCaptor> argument = newJavaCommandArgumentCaptor();
verify(monitor).start(argument.capture());
- assertThat(argument.getValue()).extracting("key").containsExactly("search", "web", "ce");
+ assertThat(argument.getValue()).extracting("processId").containsExactly(ProcessId.ELASTICSEARCH, ProcessId.WEB_SERVER, ProcessId.COMPUTE_ENGINE);
}
@Test
@@ -75,7 +76,7 @@ public class AppTest {
ArgumentCaptor> argument = newJavaCommandArgumentCaptor();
verify(monitor).start(argument.capture());
- assertThat(argument.getValue()).extracting("key").containsOnly("search");
+ assertThat(argument.getValue()).extracting("processId").containsOnly(ProcessId.ELASTICSEARCH);
}
@Test
--
2.39.5