From 975158a5a726aa67c093f85779ac2c97efd03bb8 Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Thu, 31 Mar 2016 12:20:55 +0200 Subject: [PATCH] SONAR-7436 replace JMX/RMI by HTTP --- pom.xml | 5 + server/sonar-ce/pom.xml | 11 +- .../container/ComputeEngineContainerImpl.java | 2 - .../ComputeEngineContainerImplTest.java | 10 +- server/sonar-process/pom.xml | 18 +- .../sonar/process/AllProcessesCommands.java | 28 +- .../sonar/process/DefaultProcessCommands.java | 8 +- .../java/org/sonar/process/{jmx => }/Jmx.java | 2 +- .../org/sonar/process/ProcessCommands.java | 4 +- .../org/sonar/process/ProcessEntryPoint.java | 14 - .../org/sonar/process/jmx/JmxConnection.java | 99 - .../systeminfo/ProcessStateSystemInfo.java | 65 + .../systeminfo/SystemInfoHttpServer.java | 104 + .../systeminfo/SystemInfoSection.java} | 30 +- .../{jmx => systeminfo}/package-info.java | 2 +- .../main/protobuf/process_system_info.proto | 43 + .../process/AllProcessesCommandsTest.java | 4 +- .../org/sonar/process/{jmx => }/JmxTest.java | 12 +- .../process/jmx/JmxConnectionFactoryTest.java | 91 - .../sonar/process/jmx/JmxConnectionTest.java | 98 - .../org/sonar/process/jmx/JmxTestServer.java | 71 - .../ProcessStateSystemInfoTest.java | 58 + .../systeminfo/SystemInfoHttpServerTest.java | 89 + .../java/org/sonar/search/EsSettings.java | 1 - .../org/sonar/search}/EsSettingsMBean.java | 2 +- .../java/org/sonar/search/SearchServer.java | 3 +- server/sonar-server/pom.xml | 9 + .../sonar/server/computation/CeModule.java | 4 + .../monitoring}/CeDatabaseMBean.java | 4 +- .../monitoring/CeDatabaseMBeanImpl.java | 22 +- .../computation/monitoring}/CeTasksMBean.java | 2 +- .../monitoring/CeTasksMBeanImpl.java | 20 +- .../platform/monitoring/BaseMonitorMBean.java | 2 +- .../monitoring/CeDatabaseMonitor.java | 65 - .../platform/monitoring/CeStateMonitor.java | 50 - .../platform/monitoring/CeTasksMonitor.java | 62 - .../platform/monitoring/DatabaseMonitor.java | 5 +- .../server/platform/monitoring/EsMonitor.java | 22 +- .../JmxConnectionFactoryProvider.java | 46 - .../platform/monitoring/JvmPropsMonitor.java | 5 +- .../server/platform/monitoring/Monitor.java | 8 +- .../platform/monitoring/PluginsMonitor.java | 5 +- .../monitoring/ProcessSystemInfoClient.java} | 54 +- .../platform/monitoring/SonarQubeMonitor.java | 5 +- .../platform/monitoring/SystemMonitor.java | 5 +- .../platformlevel/PlatformLevel4.java | 12 +- .../sonar/server/platform/ws/InfoAction.java | 45 +- .../monitoring/CeDatabaseMBeanImplTest.java | 70 + .../monitoring/CeTasksMBeanImplTest.java | 9 +- .../monitoring/CeDatabaseMonitorTest.java | 61 - .../monitoring/CeStateMonitorTest.java | 61 - .../monitoring/CeTasksMonitorTest.java | 61 - .../monitoring/DatabaseMonitorTest.java | 4 +- .../platform/monitoring/EsMonitorTest.java | 22 +- .../monitoring/EsStateMonitorTest.java | 60 - .../platform/monitoring/FakeMonitor.java | 5 +- .../JmxConnectionFactoryProviderTest.java | 56 - .../monitoring/JvmPropsMonitorTest.java | 5 +- .../monitoring/PluginsMonitorTest.java | 2 +- .../ProcessSystemInfoClientTest.java | 99 + .../monitoring/SonarQubeMonitorTest.java | 17 +- .../monitoring/SystemMonitorTest.java | 2 +- .../server/platform/ws/InfoActionTest.java | 15 +- .../server/platform/ws/SystemWsTest.java | 5 +- sonar-application/assembly.xml | 4 +- .../apache/struts/resources/web-app_2_3.dtd | 1818 ++++++++--------- 66 files changed, 1689 insertions(+), 2013 deletions(-) rename server/sonar-process/src/main/java/org/sonar/process/{jmx => }/Jmx.java (99%) delete 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/systeminfo/ProcessStateSystemInfo.java create mode 100644 server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoHttpServer.java rename server/{sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStateMonitor.java => sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoSection.java} (50%) rename server/sonar-process/src/main/java/org/sonar/process/{jmx => systeminfo}/package-info.java (96%) create mode 100644 server/sonar-process/src/main/protobuf/process_system_info.proto rename server/sonar-process/src/test/java/org/sonar/process/{jmx => }/JmxTest.java (89%) delete mode 100644 server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionFactoryTest.java delete mode 100644 server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionTest.java delete mode 100644 server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTestServer.java create mode 100644 server/sonar-process/src/test/java/org/sonar/process/systeminfo/ProcessStateSystemInfoTest.java create mode 100644 server/sonar-process/src/test/java/org/sonar/process/systeminfo/SystemInfoHttpServerTest.java rename server/{sonar-process/src/main/java/org/sonar/process/jmx => sonar-search/src/main/java/org/sonar/search}/EsSettingsMBean.java (97%) rename server/{sonar-process/src/main/java/org/sonar/process/jmx => sonar-server/src/main/java/org/sonar/server/computation/monitoring}/CeDatabaseMBean.java (90%) rename server/{sonar-process/src/main/java/org/sonar/process/jmx => sonar-server/src/main/java/org/sonar/server/computation/monitoring}/CeTasksMBean.java (97%) delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeDatabaseMonitor.java delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeStateMonitor.java delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeTasksMonitor.java delete mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JmxConnectionFactoryProvider.java rename server/{sonar-process/src/main/java/org/sonar/process/jmx/JmxConnectionFactory.java => sonar-server/src/main/java/org/sonar/server/platform/monitoring/ProcessSystemInfoClient.java} (51%) create mode 100644 server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CeDatabaseMBeanImplTest.java delete mode 100644 server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeDatabaseMonitorTest.java delete mode 100644 server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeStateMonitorTest.java delete mode 100644 server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeTasksMonitorTest.java delete mode 100644 server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/EsStateMonitorTest.java delete mode 100644 server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JmxConnectionFactoryProviderTest.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/ProcessSystemInfoClientTest.java diff --git a/pom.xml b/pom.xml index 6bb1a156a7c..e5516516da1 100644 --- a/pom.xml +++ b/pom.xml @@ -673,6 +673,11 @@ mybatis 3.2.7 + + org.nanohttpd + nanohttpd + 2.3.0 + org.picocontainer picocontainer diff --git a/server/sonar-ce/pom.xml b/server/sonar-ce/pom.xml index f9ead798b1d..593799b9ad5 100644 --- a/server/sonar-ce/pom.xml +++ b/server/sonar-ce/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.sonarsource.sonarqube @@ -17,6 +18,14 @@ ${project.version} provided + + org.nanohttpd + nanohttpd + + + com.google.protobuf + protobuf-java + com.google.code.findbugs 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 cc98def1ecf..12a117288d9 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 @@ -104,7 +104,6 @@ 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.JmxConnectionFactoryProvider; import org.sonar.server.plugins.InstalledPluginReferentialFactory; import org.sonar.server.plugins.ServerExtensionInstaller; import org.sonar.server.plugins.privileged.PrivilegedPluginsBootstraper; @@ -137,7 +136,6 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { private static final Object[] LEVEL_1_COMPONENTS = new Object[] { ComputeEngineSettings.class, SonarQubeVersionFactory.create(System2.INSTANCE), - new JmxConnectionFactoryProvider(), ServerImpl.class, UuidFactoryImpl.INSTANCE, // no EmbeddedDatabaseFactory.class, creating H2 DB if responsibility of WebServer 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 4345cd88fe4..66d1080984f 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 @@ -31,9 +31,12 @@ import org.picocontainer.MutablePicoContainer; import org.sonar.api.database.DatabaseProperties; import org.sonar.api.utils.System2; import org.sonar.db.DbTester; +import org.sonar.process.ProcessId; import org.sonar.process.Props; +import static java.lang.String.valueOf; import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_INDEX; 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; @@ -62,10 +65,11 @@ public class ComputeEngineContainerImplTest { File homeDir = tempFolder.newFolder(); File dataDir = new File(homeDir, "data"); File tmpDir = new File(homeDir, "tmp"); - properties.setProperty(STARTED_AT, String.valueOf(new Date().getTime())); + properties.setProperty(STARTED_AT, valueOf(new Date().getTime())); properties.setProperty(PATH_HOME, homeDir.getAbsolutePath()); properties.setProperty(PATH_DATA, dataDir.getAbsolutePath()); properties.setProperty(PATH_TEMP, tmpDir.getAbsolutePath()); + properties.setProperty(PROPERTY_PROCESS_INDEX, valueOf(ProcessId.COMPUTE_ENGINE.getIpcIndex())); properties.setProperty(PROPERTY_SHARED_PATH, tmpDir.getAbsolutePath()); String url = ((BasicDataSource) dbTester.database().getDataSource()).getUrl(); properties.setProperty(DatabaseProperties.PROP_URL, url); @@ -80,7 +84,7 @@ public class ComputeEngineContainerImplTest { .hasSize( CONTAINER_ITSELF + 75 // level 4 - + 5 // content of CeModule + + 7 // content of CeModule + 7 // content of CeQueueModule + 4 // content of ReportProcessingModule + 4 // content of CeTaskProcessorModule @@ -95,7 +99,7 @@ public class ComputeEngineContainerImplTest { ); assertThat(picoContainer.getParent().getParent().getParent().getComponentAdapters()).hasSize( COMPONENTS_IN_LEVEL_1_AT_CONSTRUCTION - + 23 // level 1 + + 22 // level 1 + 45 // content of DaoModule + 1 // content of EsSearchModule + 56 // content of CorePropertyDefinitions diff --git a/server/sonar-process/pom.xml b/server/sonar-process/pom.xml index 3bd9cfc33d7..ee7d279fc2f 100644 --- a/server/sonar-process/pom.xml +++ b/server/sonar-process/pom.xml @@ -29,12 +29,23 @@ commons-lang commons-lang - com.google.code.findbugs jsr305 provided + + + org.nanohttpd + nanohttpd + true + + + + com.google.protobuf + protobuf-java + true + ${project.groupId} @@ -56,6 +67,11 @@ jetty-server test + + com.squareup.okhttp + okhttp + test + 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 9652aca6795..f5e0954f6ff 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 @@ -69,11 +69,11 @@ public class AllProcessesCommands implements AutoCloseable { 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 SYSTEM_INFO_URL_BYTE_OFFSET = PING_BYTE_OFFSET + 8; - private static final int JMX_URL_SIZE_IN_BYTES = 500; + private static final int SYSTEM_INFO_URL_SIZE_IN_BYTES = 500; - private static final int BYTE_LENGTH_FOR_ONE_PROCESS = 1 + 1 + 1 + 1 + 8 + JMX_URL_SIZE_IN_BYTES; + private static final int BYTE_LENGTH_FOR_ONE_PROCESS = 1 + 1 + 1 + 1 + 8 + SYSTEM_INFO_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; @@ -148,17 +148,17 @@ public class AllProcessesCommands implements AutoCloseable { return readLong(processNumber, PING_BYTE_OFFSET); } - String getJmxUrl(int processNumber) { - byte[] urlBytes = readBytes(processNumber, JMX_URL_BYTE_OFFSET, JMX_URL_SIZE_IN_BYTES); + String getSystemInfoUrl(int processNumber) { + byte[] urlBytes = readBytes(processNumber, SYSTEM_INFO_URL_BYTE_OFFSET, SYSTEM_INFO_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)); + void setSystemInfoUrl(int processNumber, String url) { + byte[] urlBytes = rightPad(url, SYSTEM_INFO_URL_SIZE_IN_BYTES).getBytes(StandardCharsets.US_ASCII); + if (urlBytes.length > SYSTEM_INFO_URL_SIZE_IN_BYTES) { + throw new IllegalArgumentException(format("System Info URL is too long. Max is %d bytes. Got: %s", SYSTEM_INFO_URL_SIZE_IN_BYTES, url)); } - writeBytes(processNumber, JMX_URL_BYTE_OFFSET, urlBytes); + writeBytes(processNumber, SYSTEM_INFO_URL_BYTE_OFFSET, urlBytes); } /** @@ -277,13 +277,13 @@ public class AllProcessesCommands implements AutoCloseable { } @Override - public void setJmxUrl(String s) { - AllProcessesCommands.this.setJmxUrl(processNumber, s); + public void setSystemInfoUrl(String s) { + AllProcessesCommands.this.setSystemInfoUrl(processNumber, s); } @Override - public String getJmxUrl() { - return AllProcessesCommands.this.getJmxUrl(processNumber); + public String getSystemInfoUrl() { + return AllProcessesCommands.this.getSystemInfoUrl(processNumber); } @Override 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 d8c9975a4ba..dade6ab6265 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 @@ -83,13 +83,13 @@ public class DefaultProcessCommands implements ProcessCommands { } @Override - public void setJmxUrl(String s) { - delegate.setJmxUrl(s); + public void setSystemInfoUrl(String s) { + delegate.setSystemInfoUrl(s); } @Override - public String getJmxUrl() { - return delegate.getJmxUrl(); + public String getSystemInfoUrl() { + return delegate.getSystemInfoUrl(); } @Override 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.java similarity index 99% rename from server/sonar-process/src/main/java/org/sonar/process/jmx/Jmx.java rename to server/sonar-process/src/main/java/org/sonar/process/Jmx.java index 62375a32e83..76a7b03c639 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/jmx/Jmx.java +++ b/server/sonar-process/src/main/java/org/sonar/process/Jmx.java @@ -17,7 +17,7 @@ * 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; +package org.sonar.process; import java.lang.management.ManagementFactory; import javax.management.InstanceAlreadyExistsException; 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 01ece9a7060..9c2f4a35a62 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 @@ -55,9 +55,9 @@ public interface ProcessCommands extends AutoCloseable { long getLastPing(); - void setJmxUrl(String s); + void setSystemInfoUrl(String s); - String getJmxUrl(); + String getSystemInfoUrl(); /** * 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 f77cc7c292a..2ca262205ce 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 @@ -22,7 +22,6 @@ package org.sonar.process; import java.io.File; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sun.misc.VMSupport; public class ProcessEntryPoint implements Stoppable { @@ -107,10 +106,6 @@ public class ProcessEntryPoint implements Stoppable { Thread.sleep(20L); } - String jmxUrl = guessJmxUrl(); - logger.debug("JMX URL is {}", jmxUrl); - commands.setJmxUrl(jmxUrl); - // notify monitor that process is ready commands.setUp(); @@ -125,15 +120,6 @@ 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/jmx/JmxConnection.java b/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnection.java deleted file mode 100644 index 4c2eaca5452..00000000000 --- a/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnection.java +++ /dev/null @@ -1,99 +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.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.LinkedHashMap; -import java.util.Map; -import javax.annotation.CheckForNull; -import javax.management.JMX; -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; -import javax.management.remote.JMXConnector; - -import static java.lang.String.format; - -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(format("Fail to connect to MBean [%s]", mBeanName), e); - } - } - - public Map getSystemState() { - Map props = new LinkedHashMap<>(); - 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/systeminfo/ProcessStateSystemInfo.java b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/ProcessStateSystemInfo.java new file mode 100644 index 00000000000..1ca9297ee33 --- /dev/null +++ b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/ProcessStateSystemInfo.java @@ -0,0 +1,65 @@ +/* + * 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.systeminfo; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.MemoryUsage; +import java.lang.management.ThreadMXBean; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +public class ProcessStateSystemInfo implements SystemInfoSection { + private static final long MEGABYTE = 1024L * 1024L; + private final String name; + + public ProcessStateSystemInfo(String name) { + this.name = name; + } + + @Override + public ProtobufSystemInfo.Section toProtobuf() { + return toProtobuf(ManagementFactory.getMemoryMXBean()); + } + + // Visible for testing + ProtobufSystemInfo.Section toProtobuf(MemoryMXBean memoryBean) { + ProtobufSystemInfo.Section.Builder builder = ProtobufSystemInfo.Section.newBuilder(); + builder.setName(name); + MemoryUsage heap = memoryBean.getHeapMemoryUsage(); + addAttributeInMb(builder, "Heap Committed (MB)", heap.getCommitted()); + addAttributeInMb(builder, "Heap Init (MB)", heap.getInit()); + addAttributeInMb(builder, "Heap Max (MB)", heap.getMax()); + addAttributeInMb(builder, "Heap Used (MB)", heap.getUsed()); + MemoryUsage nonHeap = memoryBean.getNonHeapMemoryUsage(); + addAttributeInMb(builder, "Non Heap Committed (MB)", nonHeap.getCommitted()); + addAttributeInMb(builder, "Non Heap Init (MB)", nonHeap.getInit()); + addAttributeInMb(builder, "Non Heap Max (MB)", nonHeap.getMax()); + addAttributeInMb(builder, "Non Heap Used (MB)", nonHeap.getUsed()); + ThreadMXBean thread = ManagementFactory.getThreadMXBean(); + builder.addAttributesBuilder().setKey("Thread Count").setLongValue(thread.getThreadCount()).build(); + return builder.build(); + } + + private void addAttributeInMb(ProtobufSystemInfo.Section.Builder builder, String key, long valueInBytes) { + if (valueInBytes >= 0L) { + builder.addAttributesBuilder().setKey(key).setLongValue(valueInBytes / MEGABYTE).build(); + } + } +} diff --git a/server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoHttpServer.java b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoHttpServer.java new file mode 100644 index 00000000000..b8c08f3b90c --- /dev/null +++ b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoHttpServer.java @@ -0,0 +1,104 @@ +/* + * 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.systeminfo; + +import fi.iki.elonen.NanoHTTPD; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.List; +import java.util.Properties; +import org.slf4j.LoggerFactory; +import org.sonar.process.DefaultProcessCommands; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +import static java.lang.Integer.parseInt; +import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_INDEX; +import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH; + +/** + * This HTTP server exports data required for display of System Info page (and the related web service). + * It listens on loopback address only, so it does not need to be secure (no HTTPS, no authentication). + */ +public class SystemInfoHttpServer { + + private static final String PROTOBUF_MIME_TYPE = "application/x-protobuf"; + + private final Properties processProps; + private final List sectionProviders; + private final SystemInfoNanoHttpd nanoHttpd; + + public SystemInfoHttpServer(Properties processProps, List sectionProviders) throws UnknownHostException { + this.processProps = processProps; + this.sectionProviders = sectionProviders; + InetAddress loopbackAddress = InetAddress.getByName(null); + this.nanoHttpd = new SystemInfoNanoHttpd(loopbackAddress.getHostAddress(), 0); + } + + // do not rename. This naming convention is required for picocontainer. + public void start() { + try { + nanoHttpd.start(); + registerHttpUrl(); + } catch (IOException e) { + throw new IllegalStateException("Can not start local HTTP server for System Info monitoring", e); + } + } + + private void registerHttpUrl() { + int processNumber = parseInt(processProps.getProperty(PROPERTY_PROCESS_INDEX)); + File shareDir = new File(processProps.getProperty(PROPERTY_SHARED_PATH)); + try (DefaultProcessCommands commands = DefaultProcessCommands.secondary(shareDir, processNumber)) { + String url = getUrl(); + commands.setSystemInfoUrl(url); + LoggerFactory.getLogger(getClass()).debug("System Info HTTP server listening at {}", url); + } + } + + // do not rename. This naming convention is required for picocontainer. + public void stop() { + nanoHttpd.stop(); + } + + // visible for testing + String getUrl() { + return "http://" + nanoHttpd.getHostname() + ":" + nanoHttpd.getListeningPort(); + } + + private class SystemInfoNanoHttpd extends NanoHTTPD { + + SystemInfoNanoHttpd(String hostname, int port) { + super(hostname, port); + } + + @Override + public Response serve(IHTTPSession session) { + ProtobufSystemInfo.SystemInfo.Builder infoBuilder = ProtobufSystemInfo.SystemInfo.newBuilder(); + for (SystemInfoSection sectionProvider : sectionProviders) { + ProtobufSystemInfo.Section section = sectionProvider.toProtobuf(); + infoBuilder.addSections(section); + } + byte[] bytes = infoBuilder.build().toByteArray(); + return newFixedLengthResponse(Response.Status.OK, PROTOBUF_MIME_TYPE, new ByteArrayInputStream(bytes), bytes.length); + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStateMonitor.java b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoSection.java similarity index 50% rename from server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStateMonitor.java rename to server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoSection.java index 779019be924..c990cacb96b 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStateMonitor.java +++ b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoSection.java @@ -17,34 +17,12 @@ * 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; +package org.sonar.process.systeminfo; -import com.google.common.base.Optional; -import java.util.Map; -import org.sonar.process.ProcessId; -import org.sonar.process.jmx.JmxConnection; -import org.sonar.process.jmx.JmxConnectionFactory; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; -public class EsStateMonitor implements Monitor { +public interface SystemInfoSection { - private final JmxConnectionFactory jmxConnectionFactory; + ProtobufSystemInfo.Section toProtobuf(); - public EsStateMonitor(JmxConnectionFactory jmxConnectionFactory) { - this.jmxConnectionFactory = jmxConnectionFactory; - } - - @Override - public String name() { - return "Elasticsearch State"; - } - - @Override - public Optional> attributes() { - try (JmxConnection connection = jmxConnectionFactory.create(ProcessId.ELASTICSEARCH)) { - if (connection == null) { - return Optional.absent(); - } - return Optional.of(connection.getSystemState()); - } - } } 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/systeminfo/package-info.java similarity index 96% rename from server/sonar-process/src/main/java/org/sonar/process/jmx/package-info.java rename to server/sonar-process/src/main/java/org/sonar/process/systeminfo/package-info.java index bb4fb97207f..3ae1af74953 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/jmx/package-info.java +++ b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/package-info.java @@ -18,6 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ @ParametersAreNonnullByDefault -package org.sonar.process.jmx; +package org.sonar.process.systeminfo; import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-process/src/main/protobuf/process_system_info.proto b/server/sonar-process/src/main/protobuf/process_system_info.proto new file mode 100644 index 00000000000..8780b677596 --- /dev/null +++ b/server/sonar-process/src/main/protobuf/process_system_info.proto @@ -0,0 +1,43 @@ +// SonarQube, open source software quality management tool. +// Copyright (C) 2008-2016 SonarSource +// mailto:contact AT sonarsource DOT com +// +// SonarQube 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. +// +// SonarQube 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. + +syntax = "proto3"; + +option java_package = "org.sonar.process.systeminfo.protobuf"; +option java_outer_classname = "ProtobufSystemInfo"; + +option optimize_for = SPEED; + +message SystemInfo { + repeated Section sections = 1; +} + +message Section { + string name = 1; + repeated Attribute attributes = 2; +} + +message Attribute { + string key = 1; + oneof value { + bool boolean_value = 2; + int64 long_value = 3; + double double_value = 4; + string string_value = 5; + } +} 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 e834fce905f..1c26836fc1e 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 @@ -105,9 +105,9 @@ public class AllProcessesCommandsTest { assertThat(readByte(commands, offset + i)).isEqualTo(EMPTY); } - commands.setJmxUrl(PROCESS_NUMBER, "jmx:foo"); + commands.setSystemInfoUrl(PROCESS_NUMBER, "jmx:foo"); assertThat(readByte(commands, offset)).isNotEqualTo(EMPTY); - assertThat(commands.getJmxUrl(PROCESS_NUMBER)).isEqualTo("jmx:foo"); + assertThat(commands.getSystemInfoUrl(PROCESS_NUMBER)).isEqualTo("jmx:foo"); } @Test 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/JmxTest.java similarity index 89% rename from server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTest.java rename to server/sonar-process/src/test/java/org/sonar/process/JmxTest.java index 9b241accac3..7df06238d94 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/JmxTest.java @@ -17,7 +17,7 @@ * 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; +package org.sonar.process; import java.lang.management.ManagementFactory; import javax.annotation.CheckForNull; @@ -27,6 +27,8 @@ import javax.management.ObjectName; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.sonar.process.jmx.Fake; +import org.sonar.process.jmx.FakeMBean; import static org.assertj.core.api.Assertions.assertThat; @@ -64,6 +66,14 @@ public class JmxTest { Jmx.register(FAKE_NAME, "not a mbean"); } + @Test + public void register_fails_if_name_is_not_valid() { + expectedException.expect(IllegalStateException.class); + expectedException.expectMessage("Can not register MBean [/]"); + + Jmx.register("/", new Fake()); + } + @Test public void support_implementation_in_different_package_than_interface() throws Exception { assertThat(lookupMBean()).isNull(); diff --git a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionFactoryTest.java b/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionFactoryTest.java deleted file mode 100644 index 4709acb83d3..00000000000 --- a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionFactoryTest.java +++ /dev/null @@ -1,91 +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.process.jmx; - -import java.io.File; -import java.util.Properties; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; -import org.sonar.process.DefaultProcessCommands; -import org.sonar.process.ProcessId; -import org.sonar.process.Props; - -import static org.assertj.core.api.Assertions.assertThat; - -public class JmxConnectionFactoryTest { - - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public JmxTestServer jmxServer = new JmxTestServer(); - - @Test - public void create_returns_null_if_process_is_down() throws Exception { - File ipcSharedDir = temp.newFolder(); - JmxConnectionFactory underTest = new JmxConnectionFactory(ipcSharedDir); - - JmxConnection connection = underTest.create(ProcessId.COMPUTE_ENGINE); - - assertThat(connection).isNull(); - } - - @Test - public void create_connection_if_process_is_up() throws Exception { - File ipcSharedDir = temp.newFolder(); - try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(ipcSharedDir, ProcessId.COMPUTE_ENGINE.getIpcIndex())) { - processCommands.setUp(); - processCommands.setJmxUrl(jmxServer.getAddress().toString()); - } - - JmxConnection connection = new JmxConnectionFactory(ipcSharedDir).create(ProcessId.COMPUTE_ENGINE); - assertThat(connection).isNotNull(); - } - - @Test - public void create_throws_ISE_if_fails_to_connect_to_process() throws Exception { - File ipcSharedDir = temp.newFolder(); - try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(ipcSharedDir, ProcessId.COMPUTE_ENGINE.getIpcIndex())) { - // process is up but does not have any JMX URL - processCommands.setUp(); - } - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Can not connect to process " + ProcessId.COMPUTE_ENGINE.toString()); - new JmxConnectionFactory(ipcSharedDir).create(ProcessId.COMPUTE_ENGINE); - } - - @Test - public void load_ipc_shared_dir_from_props() throws Exception { - File ipcSharedDir = temp.newFolder(); - Properties props = new Properties(); - props.setProperty("process.sharedDir", ipcSharedDir.getAbsolutePath()); - - JmxConnectionFactory underTest = new JmxConnectionFactory(new Props(props)); - - assertThat(underTest.getIpcSharedDir().getCanonicalPath()).isEqualTo(ipcSharedDir.getCanonicalPath()); - } - -} 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 deleted file mode 100644 index efb7f83701f..00000000000 --- a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxConnectionTest.java +++ /dev/null @@ -1,98 +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.process.jmx; - -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; -import java.util.Map; -import javax.management.ObjectName; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static org.assertj.core.api.Assertions.assertThat; - -public class JmxConnectionTest { - - private static final String CUSTOM_OBJECT_NAME = "Test:name=test"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Rule - public JmxTestServer jmxServer = new JmxTestServer(); - - JmxConnection underTest; - - @Before - public void setUp() throws Exception { - jmxServer.getMBeanServer().registerMBean(new Fake(), new ObjectName(CUSTOM_OBJECT_NAME)); - JMXConnector jmxConnector = JMXConnectorFactory.newJMXConnector(jmxServer.getAddress(), null); - jmxConnector.connect(); - underTest = new JmxConnection(jmxConnector); - } - - @After - public void tearDown() throws Exception { - underTest.close(); - jmxServer.getMBeanServer().unregisterMBean(new ObjectName(CUSTOM_OBJECT_NAME)); - } - - @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); - } - - @Test - public void get_platform_mbean() throws Exception { - RuntimeMXBean runtimeMBean = underTest.getMBean(ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class); - - assertThat(runtimeMBean).isNotNull(); - } - - @Test - public void get_custom_mbean() throws Exception { - FakeMBean mbean = underTest.getMBean(CUSTOM_OBJECT_NAME, FakeMBean.class); - - assertThat(mbean).isNotNull(); - } - - @Test - public void getMBean_fails_if_does_not_exist() throws Exception { - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Fail to connect to MBean [unknown]"); - underTest.getMBean("unknown", FakeMBean.class); - } - - @Test - public void getSystemState() throws Exception { - Map state = underTest.getSystemState(); - assertThat(state).containsKey("Heap Max (MB)"); - assertThat((int) state.get("Thread Count")).isGreaterThan(0); - } -} diff --git a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTestServer.java b/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTestServer.java deleted file mode 100644 index 9ffe8413bef..00000000000 --- a/server/sonar-process/src/test/java/org/sonar/process/jmx/JmxTestServer.java +++ /dev/null @@ -1,71 +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.process.jmx; - -import com.google.common.base.Throwables; -import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.rmi.registry.LocateRegistry; -import java.util.HashMap; -import javax.management.MBeanServer; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXConnectorServerFactory; -import javax.management.remote.JMXServiceURL; -import org.junit.rules.ExternalResource; -import org.sonar.process.NetworkUtils; - -public class JmxTestServer extends ExternalResource { - - private final int jmxPort = NetworkUtils.freePort(); - private JMXConnectorServer jmxServer; - - @Override - protected void before() throws Throwable { - LocateRegistry.createRegistry(jmxPort); - JMXServiceURL serviceUrl = new JMXServiceURL("service:jmx:rmi://localhost:" + jmxPort + "/jndi/rmi://localhost:" + jmxPort + "/jmxrmi"); - MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); - jmxServer = JMXConnectorServerFactory.newJMXConnectorServer(serviceUrl, new HashMap(), mbeanServer); - jmxServer.start(); - - } - - @Override - protected void after() { - if (jmxServer != null) { - try { - jmxServer.stop(); - } catch (IOException e) { - throw Throwables.propagate(e); - } - } - } - - public int getPort() { - return jmxPort; - } - - public MBeanServer getMBeanServer() { - return jmxServer.getMBeanServer(); - } - - public JMXServiceURL getAddress() { - return jmxServer.getAddress(); - } -} diff --git a/server/sonar-process/src/test/java/org/sonar/process/systeminfo/ProcessStateSystemInfoTest.java b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/ProcessStateSystemInfoTest.java new file mode 100644 index 00000000000..b1088a07584 --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/ProcessStateSystemInfoTest.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.process.systeminfo; + +import java.lang.management.MemoryMXBean; +import org.junit.Test; +import org.mockito.Mockito; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ProcessStateSystemInfoTest { + + public static final String PROCESS_NAME = "the process name"; + + @Test + public void toSystemInfoSection() { + ProcessStateSystemInfo underTest = new ProcessStateSystemInfo(PROCESS_NAME); + ProtobufSystemInfo.Section section = underTest.toProtobuf(); + + assertThat(section.getName()).isEqualTo(PROCESS_NAME); + assertThat(section.getAttributesCount()).isEqualTo(9); + assertThat(section.getAttributes(0).getKey()).isEqualTo("Heap Committed (MB)"); + assertThat(section.getAttributes(0).getLongValue()).isGreaterThan(1L); + assertThat(section.getAttributes(8).getKey()).isEqualTo("Thread Count"); + assertThat(section.getAttributes(8).getLongValue()).isGreaterThan(1L); + } + + @Test + public void should_hide_attributes_without_values() { + MemoryMXBean memoryBean = mock(MemoryMXBean.class, Mockito.RETURNS_DEEP_STUBS); + when(memoryBean.getHeapMemoryUsage().getCommitted()).thenReturn(-1L); + + ProcessStateSystemInfo underTest = new ProcessStateSystemInfo(PROCESS_NAME); + ProtobufSystemInfo.Section section = underTest.toProtobuf(memoryBean); + + assertThat(section.getAttributesList()).extracting("key").doesNotContain("Heap Committed (MB)"); + } +} diff --git a/server/sonar-process/src/test/java/org/sonar/process/systeminfo/SystemInfoHttpServerTest.java b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/SystemInfoHttpServerTest.java new file mode 100644 index 00000000000..31f7f48f08f --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/SystemInfoHttpServerTest.java @@ -0,0 +1,89 @@ +/* + * 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.systeminfo; + +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; +import java.io.IOException; +import java.net.ConnectException; +import java.util.Arrays; +import java.util.Properties; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.process.ProcessEntryPoint.PROPERTY_PROCESS_INDEX; +import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH; + +public class SystemInfoHttpServerTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + SystemInfoSection stateProvider1 = new ProcessStateSystemInfo("state1"); + SystemInfoSection stateProvider2 = new ProcessStateSystemInfo("state2"); + SystemInfoHttpServer underTest; + + @Before + public void setUp() throws Exception { + Properties properties = new Properties(); + properties.setProperty(PROPERTY_PROCESS_INDEX, "1"); + properties.setProperty(PROPERTY_SHARED_PATH, temp.newFolder().getAbsolutePath()); + underTest = new SystemInfoHttpServer(properties, Arrays.asList(stateProvider1, stateProvider2)); + } + + @After + public void tearDown() { + underTest.stop(); + } + + @Test + public void start_starts_http_server_and_publishes_URL_in_IPC() throws Exception { + underTest.start(); + Response response = call(underTest.getUrl()); + assertThat(response.code()).isEqualTo(200); + ProtobufSystemInfo.SystemInfo systemInfo = ProtobufSystemInfo.SystemInfo.parseFrom(response.body().bytes()); + assertThat(systemInfo.getSectionsCount()).isEqualTo(2); + assertThat(systemInfo.getSections(0).getName()).isEqualTo("state1"); + assertThat(systemInfo.getSections(1).getName()).isEqualTo("state2"); + } + + @Test + public void stop_stops_http_server() throws Exception { + underTest.start(); + underTest.stop(); + expectedException.expect(ConnectException.class); + call(underTest.getUrl()); + } + + private static Response call(String url) throws IOException { + Request request = new Request.Builder().get().url(url).build(); + return new OkHttpClient().newCall(request).execute(); + } +} diff --git a/server/sonar-search/src/main/java/org/sonar/search/EsSettings.java b/server/sonar-search/src/main/java/org/sonar/search/EsSettings.java index 2f0986e1e45..50802429918 100644 --- a/server/sonar-search/src/main/java/org/sonar/search/EsSettings.java +++ b/server/sonar-search/src/main/java/org/sonar/search/EsSettings.java @@ -33,7 +33,6 @@ 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; public class EsSettings implements EsSettingsMBean { diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/EsSettingsMBean.java b/server/sonar-search/src/main/java/org/sonar/search/EsSettingsMBean.java similarity index 97% rename from server/sonar-process/src/main/java/org/sonar/process/jmx/EsSettingsMBean.java rename to server/sonar-search/src/main/java/org/sonar/search/EsSettingsMBean.java index 197dc35051c..9d5d2a4e712 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/jmx/EsSettingsMBean.java +++ b/server/sonar-search/src/main/java/org/sonar/search/EsSettingsMBean.java @@ -17,7 +17,7 @@ * 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; +package org.sonar.search; /** * MBean registered in the Elasticsearch process 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 31541ad259f..eda960f22b3 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 @@ -22,12 +22,11 @@ package org.sonar.search; import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.node.internal.InternalNode; +import org.sonar.process.Jmx; 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 { diff --git a/server/sonar-server/pom.xml b/server/sonar-server/pom.xml index 2b1a4860dbb..12253497147 100644 --- a/server/sonar-server/pom.xml +++ b/server/sonar-server/pom.xml @@ -159,6 +159,10 @@ org.elasticsearch elasticsearch + + com.google.protobuf + protobuf-java + ${project.groupId} sonar-ws @@ -223,6 +227,11 @@ subethasmtp test + + com.squareup.okhttp + mockwebserver + test + 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 4cdf80747d4..2051a4929e2 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 @@ -22,6 +22,8 @@ package org.sonar.server.computation; import org.sonar.ce.log.CeLogging; import org.sonar.core.platform.Module; import org.sonar.db.purge.period.DefaultPeriodCleaner; +import org.sonar.process.systeminfo.ProcessStateSystemInfo; +import org.sonar.process.systeminfo.SystemInfoHttpServer; import org.sonar.server.computation.configuration.CeConfigurationImpl; import org.sonar.server.computation.dbcleaner.IndexPurgeListener; import org.sonar.server.computation.dbcleaner.ProjectCleaner; @@ -37,6 +39,8 @@ public class CeModule extends Module { CeConfigurationImpl.class, CeLogging.class, CeDatabaseMBeanImpl.class, + SystemInfoHttpServer.class, + new ProcessStateSystemInfo("Compute Engine State"), DefaultPeriodCleaner.class, ProjectCleaner.class, diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/CeDatabaseMBean.java b/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeDatabaseMBean.java similarity index 90% rename from server/sonar-process/src/main/java/org/sonar/process/jmx/CeDatabaseMBean.java rename to server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeDatabaseMBean.java index 354ce0db734..6f20edc66c4 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/jmx/CeDatabaseMBean.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeDatabaseMBean.java @@ -17,11 +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.process.jmx; +package org.sonar.server.computation.monitoring; public interface CeDatabaseMBean { - String OBJECT_NAME = "SonarQube:name=ComputeEngineDatabase"; + String OBJECT_NAME = "SonarQube:name=ComputeEngineDatabaseConnection"; int getPoolActiveConnections(); 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 index 4b7e43a3fa5..e0315abcad4 100644 --- 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 @@ -22,10 +22,11 @@ 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; +import org.sonar.process.Jmx; +import org.sonar.process.systeminfo.SystemInfoSection; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; -public class CeDatabaseMBeanImpl implements CeDatabaseMBean, Startable { +public class CeDatabaseMBeanImpl implements CeDatabaseMBean, Startable, SystemInfoSection { private final DbClient dbClient; public CeDatabaseMBeanImpl(DbClient dbClient) { @@ -94,4 +95,19 @@ public class CeDatabaseMBeanImpl implements CeDatabaseMBean, Startable { return (BasicDataSource) dbClient.getDatabase().getDataSource(); } + @Override + public ProtobufSystemInfo.Section toProtobuf() { + ProtobufSystemInfo.Section.Builder builder = ProtobufSystemInfo.Section.newBuilder(); + builder.setName("Compute Engine Database Connection"); + builder.addAttributesBuilder().setKey("Pool Initial Size").setLongValue(getPoolInitialSize()).build(); + builder.addAttributesBuilder().setKey("Pool Active Connections").setLongValue(getPoolActiveConnections()).build(); + builder.addAttributesBuilder().setKey("Pool Idle Connections").setLongValue(getPoolIdleConnections()).build(); + builder.addAttributesBuilder().setKey("Pool Max Active Connections").setLongValue(getPoolMaxActiveConnections()).build(); + builder.addAttributesBuilder().setKey("Pool Max Idle Connections").setLongValue(getPoolMaxIdleConnections()).build(); + builder.addAttributesBuilder().setKey("Pool Min Idle Connections").setLongValue(getPoolMinIdleConnections()).build(); + builder.addAttributesBuilder().setKey("Pool Max Wait (ms)").setLongValue(getPoolMaxWaitMillis()).build(); + builder.addAttributesBuilder().setKey("Pool Remove Abandoned").setBooleanValue(getPoolRemoveAbandoned()).build(); + builder.addAttributesBuilder().setKey("Pool Remove Abandoned Timeout (sec)").setLongValue(getPoolRemoveAbandonedTimeoutSeconds()).build(); + return builder.build(); + } } diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/CeTasksMBean.java b/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeTasksMBean.java similarity index 97% rename from server/sonar-process/src/main/java/org/sonar/process/jmx/CeTasksMBean.java rename to server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeTasksMBean.java index 968dabc52b2..227e9f6be8c 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/jmx/CeTasksMBean.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeTasksMBean.java @@ -17,7 +17,7 @@ * 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; +package org.sonar.server.computation.monitoring; public interface CeTasksMBean { diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeTasksMBeanImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeTasksMBeanImpl.java index 57b08e356de..df7e68ec989 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeTasksMBeanImpl.java +++ b/server/sonar-server/src/main/java/org/sonar/server/computation/monitoring/CeTasksMBeanImpl.java @@ -21,11 +21,12 @@ package org.sonar.server.computation.monitoring; 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.process.Jmx; +import org.sonar.process.systeminfo.SystemInfoSection; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; import org.sonar.server.computation.configuration.CeConfiguration; -public class CeTasksMBeanImpl implements CeTasksMBean, Startable { +public class CeTasksMBeanImpl implements CeTasksMBean, Startable, SystemInfoSection { private final CEQueueStatus queueStatus; private final CeConfiguration ceConfiguration; @@ -76,4 +77,17 @@ public class CeTasksMBeanImpl implements CeTasksMBean, Startable { public int getWorkerCount() { return ceConfiguration.getWorkerCount(); } + + @Override + public ProtobufSystemInfo.Section toProtobuf() { + ProtobufSystemInfo.Section.Builder builder = ProtobufSystemInfo.Section.newBuilder(); + builder.setName("Compute Engine Tasks"); + builder.addAttributesBuilder().setKey("Pending").setLongValue(getPendingCount()).build(); + builder.addAttributesBuilder().setKey("In Progress").setLongValue(getInProgressCount()).build(); + builder.addAttributesBuilder().setKey("Processed With Error").setLongValue(getErrorCount()).build(); + builder.addAttributesBuilder().setKey("Processed With Success").setLongValue(getSuccessCount()).build(); + builder.addAttributesBuilder().setKey("Processing Time (ms)").setLongValue(getProcessingTime()).build(); + builder.addAttributesBuilder().setKey("Worker Count").setLongValue(getWorkerCount()).build(); + return builder.build(); + } } 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 b56d9a9346e..44f63304eec 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,7 +20,7 @@ package org.sonar.server.platform.monitoring; import org.picocontainer.Startable; -import org.sonar.process.jmx.Jmx; +import org.sonar.process.Jmx; /** * Base implementation of a {@link org.sonar.server.platform.monitoring.Monitor} 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 deleted file mode 100644 index 052d3ff5634..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeDatabaseMonitor.java +++ /dev/null @@ -1,65 +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.server.platform.monitoring; - -import com.google.common.base.Optional; -import java.util.LinkedHashMap; -import java.util.Map; -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 static final int NUMBER_OF_ATTRIBUTES = 9; - - private final JmxConnectionFactory jmxConnectionFactory; - - public CeDatabaseMonitor(JmxConnectionFactory jmxConnectionFactory) { - this.jmxConnectionFactory = jmxConnectionFactory; - } - - @Override - public String name() { - return "Compute Engine Database Connection"; - } - - @Override - public Optional> attributes() { - try (JmxConnection connection = jmxConnectionFactory.create(ProcessId.COMPUTE_ENGINE)) { - if (connection == null) { - return Optional.absent(); - } - Map result = new LinkedHashMap<>(NUMBER_OF_ATTRIBUTES); - 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 Optional.of(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 deleted file mode 100644 index d920607edb6..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeStateMonitor.java +++ /dev/null @@ -1,50 +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.server.platform.monitoring; - -import com.google.common.base.Optional; -import java.util.Map; -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 Optional> attributes() { - try (JmxConnection connection = jmxConnectionFactory.create(ProcessId.COMPUTE_ENGINE)) { - if (connection == null) { - return Optional.absent(); - } - return Optional.of(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 deleted file mode 100644 index fbdd08ba5dd..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/CeTasksMonitor.java +++ /dev/null @@ -1,62 +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.server.platform.monitoring; - -import com.google.common.base.Optional; -import java.util.LinkedHashMap; -import java.util.Map; -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 static final int NUMBER_OF_ATTRIBUTES = 6; - - private final JmxConnectionFactory jmxConnectionFactory; - - public CeTasksMonitor(JmxConnectionFactory jmxConnectionFactory) { - this.jmxConnectionFactory = jmxConnectionFactory; - } - - @Override - public String name() { - return "Compute Engine Tasks"; - } - - @Override - public Optional> attributes() { - try (JmxConnection connection = jmxConnectionFactory.create(ProcessId.COMPUTE_ENGINE)) { - if (connection == null) { - return Optional.absent(); - } - Map result = new LinkedHashMap<>(NUMBER_OF_ATTRIBUTES); - 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 Optional.of(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 f71f841b6e6..4e957180552 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,7 +19,6 @@ */ package org.sonar.server.platform.monitoring; -import com.google.common.base.Optional; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; @@ -101,11 +100,11 @@ public class DatabaseMonitor extends BaseMonitorMBean implements DatabaseMonitor } @Override - public Optional> attributes() { + public Map attributes() { Map attributes = new LinkedHashMap<>(); completeDbAttributes(attributes); completePoolAttributes(attributes); - return Optional.of(attributes); + return attributes; } private void completePoolAttributes(Map attributes) { 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 686ae56880a..7f37d2b0f31 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 @@ -19,7 +19,6 @@ */ package org.sonar.server.platform.monitoring; -import com.google.common.base.Optional; import java.util.LinkedHashMap; import java.util.Map; import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus; @@ -30,21 +29,15 @@ 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(JmxConnectionFactory jmxConnectionFactory, EsClient esClient) { - this.jmxConnectionFactory = jmxConnectionFactory; + public EsMonitor(EsClient esClient) { this.esClient = esClient; } @@ -72,22 +65,13 @@ public class EsMonitor extends BaseMonitorMBean implements EsMonitorMBean { } @Override - public Optional> attributes() { + public Map attributes() { Map attributes = new LinkedHashMap<>(); - - try (JmxConnection connection = jmxConnectionFactory.create(ProcessId.ELASTICSEARCH)) { - if (connection != null) { - 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()); attributes.put("Nodes", nodeAttributes()); - return Optional.of(attributes); + return attributes; } private LinkedHashMap> indexAttributes() { diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JmxConnectionFactoryProvider.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JmxConnectionFactoryProvider.java deleted file mode 100644 index ebc98c1dddf..00000000000 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JmxConnectionFactoryProvider.java +++ /dev/null @@ -1,46 +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.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 JmxConnectionFactoryProvider 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/JvmPropsMonitor.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JvmPropsMonitor.java index 26f642b7e6b..d49a1e172d5 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JvmPropsMonitor.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/JvmPropsMonitor.java @@ -19,7 +19,6 @@ */ package org.sonar.server.platform.monitoring; -import com.google.common.base.Optional; import java.util.Map; import java.util.Objects; import java.util.TreeMap; @@ -31,11 +30,11 @@ public class JvmPropsMonitor implements Monitor { } @Override - public Optional> attributes() { + public Map attributes() { Map sortedProps = new TreeMap<>(); for (Map.Entry systemProp : System.getProperties().entrySet()) { sortedProps.put(Objects.toString(systemProp.getKey()), Objects.toString(systemProp.getValue())); } - return Optional.of(sortedProps); + return sortedProps; } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/Monitor.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/Monitor.java index d4d6808865a..a268b43e5fe 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/Monitor.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/Monitor.java @@ -19,9 +19,7 @@ */ package org.sonar.server.platform.monitoring; -import com.google.common.base.Optional; import java.util.Map; -import org.sonar.api.ce.ComputeEngineSide; import org.sonar.api.server.ServerSide; import org.sonar.server.platform.ws.InfoAction; @@ -29,7 +27,6 @@ import org.sonar.server.platform.ws.InfoAction; * Any component that is involved in the information returned by the web service api/system/info */ @ServerSide -@ComputeEngineSide public interface Monitor { /** * Name of section in System Info page @@ -39,9 +36,6 @@ public interface Monitor { /** * Type of attribute values must be supported by {@link org.sonar.api.utils.text.JsonWriter#valueObject(Object)} * because of JSON export by {@link InfoAction}. - * - * @return map of attributes, or Optional.absent() if the monitored component is not up. In the latter case - * nothing is returned in the web service api/system/info. */ - Optional> attributes(); + Map attributes(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/PluginsMonitor.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/PluginsMonitor.java index 6edb3cef096..afed7b16f48 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/PluginsMonitor.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/PluginsMonitor.java @@ -19,7 +19,6 @@ */ package org.sonar.server.platform.monitoring; -import com.google.common.base.Optional; import java.util.LinkedHashMap; import java.util.Map; import org.sonar.core.platform.PluginInfo; @@ -42,7 +41,7 @@ public class PluginsMonitor implements Monitor { } @Override - public Optional> attributes() { + public Map attributes() { Map attributes = new LinkedHashMap<>(); for (PluginInfo plugin : repository.getPluginInfos()) { LinkedHashMap pluginAttributes = new LinkedHashMap<>(); @@ -53,6 +52,6 @@ public class PluginsMonitor implements Monitor { } attributes.put(plugin.getKey(), pluginAttributes); } - return Optional.of(attributes); + return attributes; } } diff --git a/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnectionFactory.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/ProcessSystemInfoClient.java similarity index 51% rename from server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnectionFactory.java rename to server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/ProcessSystemInfoClient.java index 29383cc211e..3968a2792a0 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/jmx/JmxConnectionFactory.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/ProcessSystemInfoClient.java @@ -17,51 +17,45 @@ * 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; +package org.sonar.server.platform.monitoring; +import com.google.common.base.Optional; import java.io.File; -import javax.annotation.CheckForNull; -import javax.annotation.concurrent.Immutable; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXServiceURL; +import java.net.URI; +import org.apache.commons.io.IOUtils; +import org.sonar.api.config.Settings; import org.sonar.process.DefaultProcessCommands; -import org.sonar.process.ProcessEntryPoint; import org.sonar.process.ProcessId; -import org.sonar.process.Props; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +import static org.sonar.process.ProcessEntryPoint.PROPERTY_SHARED_PATH; /** - * Connects to JMX of other JVM processes + * Connects to the System Info HTTP server of another JVM process. */ -@Immutable -public class JmxConnectionFactory { - private final File ipcSharedDir; +public class ProcessSystemInfoClient { - public JmxConnectionFactory(File ipcSharedDir) { - this.ipcSharedDir = ipcSharedDir; - } + private final File ipcSharedDir; - public JmxConnectionFactory(Props props) { - this.ipcSharedDir = props.nonNullValueAsFile(ProcessEntryPoint.PROPERTY_SHARED_PATH); + public ProcessSystemInfoClient(Settings props) { + this.ipcSharedDir = new File(props.getString(PROPERTY_SHARED_PATH)); } - @CheckForNull - public JmxConnection create(ProcessId processId) { + /** + * Connects to the specified JVM process and requests system information. + * @return the system info, or absent if the process is not up or if its HTTP URL + * is not registered into IPC. + */ + public Optional connect(ProcessId processId) { try (DefaultProcessCommands commands = DefaultProcessCommands.secondary(ipcSharedDir, processId.getIpcIndex())) { if (commands.isUp()) { - String url = commands.getJmxUrl(); - JMXConnector jmxConnector = JMXConnectorFactory.newJMXConnector(new JMXServiceURL(url), null); - jmxConnector.connect(); - return new JmxConnection(jmxConnector); + String url = commands.getSystemInfoUrl(); + byte[] protobuf = IOUtils.toByteArray(new URI(url)); + return Optional.of(ProtobufSystemInfo.SystemInfo.parseFrom(protobuf)); } - return null; + return Optional.absent(); } catch (Exception e) { - throw new IllegalStateException("Can not connect to process " + processId, e); + throw new IllegalStateException("Can not get system info of process " + processId, e); } } - - // visible for testing - File getIpcSharedDir() { - return ipcSharedDir; - } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SonarQubeMonitor.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SonarQubeMonitor.java index 7d6c3bd00ba..ab513629d81 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SonarQubeMonitor.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SonarQubeMonitor.java @@ -19,7 +19,6 @@ */ package org.sonar.server.platform.monitoring; -import com.google.common.base.Optional; import java.io.File; import java.util.LinkedHashMap; import java.util.Map; @@ -97,7 +96,7 @@ public class SonarQubeMonitor extends BaseMonitorMBean implements SonarQubeMonit } @Override - public Optional> attributes() { + public Map attributes() { Map attributes = new LinkedHashMap<>(); attributes.put("Server ID", getServerId()); attributes.put("Version", getVersion()); @@ -111,7 +110,7 @@ public class SonarQubeMonitor extends BaseMonitorMBean implements SonarQubeMonit attributes.put("Temp Dir", settings.getString(ProcessProperties.PATH_TEMP)); attributes.put("Logs Dir", settings.getString(ProcessProperties.PATH_LOGS)); attributes.put("Logs Level", getLogLevel()); - return Optional.of(attributes); + return attributes; } } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SystemMonitor.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SystemMonitor.java index d7d279d94c9..b5788d847ae 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SystemMonitor.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SystemMonitor.java @@ -19,7 +19,6 @@ */ package org.sonar.server.platform.monitoring; -import com.google.common.base.Optional; import java.lang.management.ClassLoadingMXBean; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; @@ -53,7 +52,7 @@ public class SystemMonitor implements Monitor { } @Override - public Optional> attributes() { + public Map attributes() { Map attributes = new LinkedHashMap<>(); attributes.put("System Date", formatDateTime(new Date(system.now()))); attributes.put("Start Time", formatDateTime(new Date(runtimeMXBean().getStartTime()))); @@ -76,7 +75,7 @@ public class SystemMonitor implements Monitor { attributes.put("Threads", threadMXBean().getThreadCount()); attributes.put("Threads Peak", threadMXBean().getPeakThreadCount()); attributes.put("Daemon Thread", threadMXBean().getDaemonThreadCount()); - return Optional.of(attributes); + return attributes; } private static RuntimeMXBean runtimeMXBean() { 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 7d4549f10a8..b617008eb74 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 @@ -149,15 +149,11 @@ 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.EsStateMonitor; -import org.sonar.server.platform.monitoring.JmxConnectionFactoryProvider; import org.sonar.server.platform.monitoring.JvmPropsMonitor; import org.sonar.server.platform.monitoring.PluginsMonitor; +import org.sonar.server.platform.monitoring.ProcessSystemInfoClient; import org.sonar.server.platform.monitoring.SonarQubeMonitor; import org.sonar.server.platform.monitoring.SystemMonitor; import org.sonar.server.platform.ws.ChangeLogLevelAction; @@ -635,7 +631,7 @@ public class PlatformLevel4 extends PlatformLevel { TypeValidationModule.class, // System - new JmxConnectionFactoryProvider(), + ProcessSystemInfoClient.class, ServerLogging.class, RestartAction.class, InfoAction.class, @@ -648,10 +644,6 @@ public class PlatformLevel4 extends PlatformLevel { PluginsMonitor.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/main/java/org/sonar/server/platform/ws/InfoAction.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/InfoAction.java index 3512a9eb632..7f68912e96d 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/InfoAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/InfoAction.java @@ -26,7 +26,10 @@ import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.text.JsonWriter; import org.sonar.core.permission.GlobalPermissions; +import org.sonar.process.ProcessId; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; import org.sonar.server.platform.monitoring.Monitor; +import org.sonar.server.platform.monitoring.ProcessSystemInfoClient; import org.sonar.server.user.UserSession; /** @@ -34,11 +37,13 @@ import org.sonar.server.user.UserSession; */ public class InfoAction implements SystemWsAction { - private final Monitor[] monitors; private final UserSession userSession; + private final ProcessSystemInfoClient processSystemInfoClient; + private final Monitor[] monitors; - public InfoAction(UserSession userSession, Monitor... monitors) { + public InfoAction(UserSession userSession, ProcessSystemInfoClient processSystemInfoClient, Monitor... monitors) { this.userSession = userSession; + this.processSystemInfoClient = processSystemInfoClient; this.monitors = monitors; } @@ -64,12 +69,38 @@ public class InfoAction implements SystemWsAction { private void writeJson(JsonWriter json) { json.beginObject(); for (Monitor monitor : monitors) { - Optional> attributes = monitor.attributes(); - if (attributes.isPresent()) { - json.name(monitor.name()); + Map attributes = monitor.attributes(); + json.name(monitor.name()); + json.beginObject(); + for (Map.Entry attribute : attributes.entrySet()) { + json.name(attribute.getKey()).valueObject(attribute.getValue()); + } + json.endObject(); + } + Optional ceSysInfo = processSystemInfoClient.connect(ProcessId.COMPUTE_ENGINE); + if (ceSysInfo.isPresent()) { + for (ProtobufSystemInfo.Section section : ceSysInfo.get().getSectionsList()) { + json.name(section.getName()); json.beginObject(); - for (Map.Entry attribute : attributes.get().entrySet()) { - json.name(attribute.getKey()).valueObject(attribute.getValue()); + for (ProtobufSystemInfo.Attribute attribute : section.getAttributesList()) { + switch (attribute.getValueCase()) { + case BOOLEAN_VALUE: + json.name(attribute.getKey()).valueObject(attribute.getBooleanValue()); + break; + case LONG_VALUE: + json.name(attribute.getKey()).valueObject(attribute.getLongValue()); + break; + case DOUBLE_VALUE: + json.name(attribute.getKey()).valueObject(attribute.getDoubleValue()); + break; + case STRING_VALUE: + json.name(attribute.getKey()).valueObject(attribute.getStringValue()); + break; + case VALUE_NOT_SET: + break; + default: + throw new IllegalArgumentException("Unsupported type: " + attribute.getValueCase()); + } } json.endObject(); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CeDatabaseMBeanImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CeDatabaseMBeanImplTest.java new file mode 100644 index 00000000000..a81a7d8d69e --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CeDatabaseMBeanImplTest.java @@ -0,0 +1,70 @@ +/* + * 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 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.sonar.api.utils.System2; +import org.sonar.db.DbTester; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CeDatabaseMBeanImplTest { + + @Rule + public DbTester dbTester = DbTester.create(System2.INSTANCE); + + CeDatabaseMBeanImpl underTest = new CeDatabaseMBeanImpl(dbTester.getDbClient()); + + @Test + public void register_and_unregister() throws Exception { + assertThat(getMBean()).isNull(); + + underTest.start(); + assertThat(getMBean()).isNotNull(); + + underTest.stop(); + assertThat(getMBean()).isNull(); + } + + @Test + public void export_system_info() { + ProtobufSystemInfo.Section section = underTest.toProtobuf(); + assertThat(section.getName()).isEqualTo("Compute Engine Database Connection"); + assertThat(section.getAttributesCount()).isEqualTo(9); + assertThat(section.getAttributes(0).getKey()).isEqualTo("Pool Initial Size"); + assertThat(section.getAttributes(0).getLongValue()).isGreaterThanOrEqualTo(0); + } + + @CheckForNull + private ObjectInstance getMBean() throws Exception { + try { + return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(CeDatabaseMBean.OBJECT_NAME)); + } catch (InstanceNotFoundException e) { + return null; + } + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CeTasksMBeanImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CeTasksMBeanImplTest.java index 9b5bc7becc8..a891f1d5569 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CeTasksMBeanImplTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/computation/monitoring/CeTasksMBeanImplTest.java @@ -26,7 +26,7 @@ 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.process.systeminfo.protobuf.ProtobufSystemInfo; import org.sonar.server.computation.configuration.CeConfiguration; import static org.assertj.core.api.Assertions.assertThat; @@ -66,6 +66,13 @@ public class CeTasksMBeanImplTest { assertThat(underTest.getWorkerCount()).isEqualTo(WORKER_COUNT); } + @Test + public void export_system_info() { + ProtobufSystemInfo.Section section = underTest.toProtobuf(); + assertThat(section.getName()).isEqualTo("Compute Engine Tasks"); + assertThat(section.getAttributesCount()).isEqualTo(6); + } + /** * Dumb implementation of CEQueueStatus which returns constant values for get methods and throws UnsupportedOperationException * for other methods. 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 deleted file mode 100644 index 9758471ffcb..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeDatabaseMonitorTest.java +++ /dev/null @@ -1,61 +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.server.platform.monitoring; - -import com.google.common.base.Optional; -import java.util.Map; -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 attributes() { - CeDatabaseMBean mbean = mock(CeDatabaseMBean.class, Mockito.RETURNS_DEFAULTS); - - when(jmxConnectionFactory.create(ProcessId.COMPUTE_ENGINE).getMBean(CeDatabaseMBean.OBJECT_NAME, CeDatabaseMBean.class)) - .thenReturn(mbean); - Optional> attributes = underTest.attributes(); - assertThat(attributes.get()).containsKeys("Pool Initial Size", "Pool Active Connections"); - assertThat(attributes.get()).hasSize(9); - } - - @Test - public void absent_attributes_if_CE_is_down() { - when(jmxConnectionFactory.create(ProcessId.COMPUTE_ENGINE)).thenReturn(null); - Optional> attributes = underTest.attributes(); - assertThat(attributes.isPresent()).isFalse(); - } -} 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 deleted file mode 100644 index 1154bcff55c..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeStateMonitorTest.java +++ /dev/null @@ -1,61 +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.server.platform.monitoring; - -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableSortedMap; -import java.util.Map; -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")); - Optional> attributes = underTest.attributes(); - assertThat(attributes.get()).containsExactly( - MapEntry.entry("bar", "bar_val"), - MapEntry.entry("foo", "foo_val")); - } - - @Test - public void absent_attributes_if_CE_is_down() { - when(jmxConnectionFactory.create(ProcessId.COMPUTE_ENGINE)).thenReturn(null); - Optional> attributes = underTest.attributes(); - assertThat(attributes.isPresent()).isFalse(); - } -} 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 deleted file mode 100644 index c9d7626aa5a..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/CeTasksMonitorTest.java +++ /dev/null @@ -1,61 +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.server.platform.monitoring; - -import com.google.common.base.Optional; -import java.util.Map; -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); - Optional> attributes = underTest.attributes(); - assertThat(attributes.get()).containsKeys("Pending"); - assertThat(attributes.get()).hasSize(6); - } - - @Test - public void absent_attributes_if_CE_is_down() { - when(jmxConnectionFactory.create(ProcessId.COMPUTE_ENGINE)).thenReturn(null); - Optional> attributes = underTest.attributes(); - assertThat(attributes.isPresent()).isFalse(); - } -} 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 5ed384ce7b0..5941af2a2ba 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 @@ -49,7 +49,7 @@ public class DatabaseMonitorTest { @Test public void db_info() { - Map attributes = underTest.attributes().get(); + Map attributes = underTest.attributes(); assertThat(attributes.get("Database")).isEqualTo("H2"); assertThat(attributes.get("Database Version").toString()).startsWith("1."); assertThat(attributes.get("Username")).isEqualTo("SONAR"); @@ -58,7 +58,7 @@ public class DatabaseMonitorTest { @Test public void pool_info() { - Map attributes = underTest.attributes().get(); + Map attributes = underTest.attributes(); assertThat((int) attributes.get("Pool Max Connections")).isGreaterThan(0); } } 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 6379c5d0779..47ec8a30311 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 @@ -21,35 +21,21 @@ package org.sonar.server.platform.monitoring; 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); - } + EsMonitor underTest = new EsMonitor(esTester.client()); @Test public void name() { @@ -58,7 +44,7 @@ public class EsMonitorTest { @Test public void cluster_attributes() { - Map attributes = underTest.attributes().get(); + Map 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); @@ -66,7 +52,7 @@ public class EsMonitorTest { @Test public void node_attributes() { - Map attributes = underTest.attributes().get(); + Map attributes = underTest.attributes(); Map nodesAttributes = (Map) attributes.get("Nodes"); // one node @@ -78,7 +64,7 @@ public class EsMonitorTest { @Test public void index_attributes() { - Map attributes = underTest.attributes().get(); + Map attributes = underTest.attributes(); Map indicesAttributes = (Map) attributes.get("Indices"); // one index "issues" 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 deleted file mode 100644 index 7618fedfbd8..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/EsStateMonitorTest.java +++ /dev/null @@ -1,60 +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.server.platform.monitoring; - -import com.google.common.base.Optional; -import com.google.common.collect.ImmutableSortedMap; -import java.util.Map; -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")); - Optional> attributes = underTest.attributes(); - assertThat(attributes.get()).containsExactly( - MapEntry.entry("bar", "bar_val"), - MapEntry.entry("foo", "foo_val")); - } - - @Test - public void absent_attributes_if_CE_is_down() { - when(jmxConnectionFactory.create(ProcessId.ELASTICSEARCH)).thenReturn(null); - Optional> attributes = underTest.attributes(); - assertThat(attributes.isPresent()).isFalse(); - } -} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/FakeMonitor.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/FakeMonitor.java index 879b65f8405..7ef3801ee09 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/FakeMonitor.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/FakeMonitor.java @@ -19,7 +19,6 @@ */ package org.sonar.server.platform.monitoring; -import com.google.common.base.Optional; import java.util.Collections; import java.util.Map; @@ -36,7 +35,7 @@ public class FakeMonitor extends BaseMonitorMBean implements FakeMonitorMBean { } @Override - public Optional> attributes() { - return Optional.of(Collections.emptyMap()); + public Map attributes() { + return Collections.emptyMap(); } } 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 deleted file mode 100644 index 03998a76cde..00000000000 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JmxConnectionFactoryProviderTest.java +++ /dev/null @@ -1,56 +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.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(); - JmxConnectionFactoryProvider underTest = new JmxConnectionFactoryProvider(); - - @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/JvmPropsMonitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JvmPropsMonitorTest.java index 0a534035280..0e8d4090f04 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JvmPropsMonitorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/JvmPropsMonitorTest.java @@ -19,7 +19,6 @@ */ package org.sonar.server.platform.monitoring; -import com.google.common.base.Optional; import java.util.Map; import org.junit.Test; @@ -36,8 +35,8 @@ public class JvmPropsMonitorTest { @Test public void attributes() { - Optional> attributes = underTest.attributes(); + Map attributes = underTest.attributes(); - assertThat(attributes.get()).containsKeys("java.vm.vendor", "os.name"); + assertThat(attributes).containsKeys("java.vm.vendor", "os.name"); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/PluginsMonitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/PluginsMonitorTest.java index c5c4b1a4f51..e3a5f374163 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/PluginsMonitorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/PluginsMonitorTest.java @@ -52,7 +52,7 @@ public class PluginsMonitorTest { new PluginInfo("no-version") .setName("No Version"))); - Map attributes = underTest.attributes().get(); + Map attributes = underTest.attributes(); assertThat(attributes).containsKeys("key-1", "key-2"); assertThat((Map) attributes.get("key-1")) diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/ProcessSystemInfoClientTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/ProcessSystemInfoClientTest.java new file mode 100644 index 00000000000..ff3016a7dfc --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/ProcessSystemInfoClientTest.java @@ -0,0 +1,99 @@ +/* + * 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.base.Optional; +import com.squareup.okhttp.mockwebserver.MockResponse; +import com.squareup.okhttp.mockwebserver.MockWebServer; +import java.io.File; +import okio.Buffer; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.config.Settings; +import org.sonar.process.DefaultProcessCommands; +import org.sonar.process.ProcessEntryPoint; +import org.sonar.process.ProcessId; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; + +public class ProcessSystemInfoClientTest { + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + @Rule + public MockWebServer server = new MockWebServer(); + + File ipcSharedDir; + ProcessSystemInfoClient underTest; + + @Before + public void setUp() throws Exception { + ipcSharedDir = temp.newFolder(); + Settings settings = new Settings(); + settings.setProperty(ProcessEntryPoint.PROPERTY_SHARED_PATH, ipcSharedDir.getAbsolutePath()); + underTest = new ProcessSystemInfoClient(settings); + } + + @Test + public void connect_returns_absent_if_process_is_down() throws Exception { + Optional info = underTest.connect(ProcessId.COMPUTE_ENGINE); + + assertThat(info.isPresent()).isFalse(); + } + + @Test + public void get_information_if_process_is_up() throws Exception { + Buffer response = new Buffer(); + response.read(ProtobufSystemInfo.Section.newBuilder().build().toByteArray()); + server.enqueue(new MockResponse().setBody(response)); + + // initialize registration of process + try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(ipcSharedDir, ProcessId.COMPUTE_ENGINE.getIpcIndex())) { + processCommands.setUp(); + processCommands.setSystemInfoUrl(format("http://%s:%d", server.getHostName(), server.getPort())); + } + + Optional info = underTest.connect(ProcessId.COMPUTE_ENGINE); + assertThat(info.get().getSectionsCount()).isEqualTo(0); + } + + @Test + public void throws_ISE_if_http_error() throws Exception { + server.enqueue(new MockResponse().setResponseCode(500)); + + // initialize registration of process + try (DefaultProcessCommands processCommands = DefaultProcessCommands.secondary(ipcSharedDir, ProcessId.COMPUTE_ENGINE.getIpcIndex())) { + processCommands.setUp(); + processCommands.setSystemInfoUrl(format("http://%s:%d", server.getHostName(), server.getPort())); + } + + expectedException.expect(IllegalStateException.class); + expectedException.expectMessage("Can not get system info of process " + ProcessId.COMPUTE_ENGINE); + underTest.connect(ProcessId.COMPUTE_ENGINE); + } +} 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 70155ae82f9..a522c1df767 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 @@ -19,7 +19,6 @@ */ package org.sonar.server.platform.monitoring; -import com.google.common.base.Optional; import java.io.File; import java.util.Map; import org.apache.commons.io.FileUtils; @@ -62,8 +61,8 @@ public class SonarQubeMonitorTest { when(server.getStartedAt()).thenReturn(DateUtils.parseDate("2015-01-01")); SonarQubeMonitor monitor = new SonarQubeMonitor(settings, new SecurityRealmFactory(settings), server, serverLogging); - Optional> attributes = monitor.attributes(); - assertThat(attributes.get()).containsKeys("Server ID", "Version"); + Map attributes = monitor.attributes(); + assertThat(attributes).containsKeys("Server ID", "Version"); } @Test @@ -74,8 +73,8 @@ public class SonarQubeMonitorTest { when(server.getRootDir()).thenReturn(rootDir); SonarQubeMonitor monitor = new SonarQubeMonitor(settings, new SecurityRealmFactory(settings), server, serverLogging); - Optional> attributes = monitor.attributes(); - assertThat(attributes.get()).containsEntry("Official Distribution", Boolean.TRUE); + Map attributes = monitor.attributes(); + assertThat(attributes).containsEntry("Official Distribution", Boolean.TRUE); } @Test @@ -85,15 +84,15 @@ public class SonarQubeMonitorTest { when(server.getRootDir()).thenReturn(rootDir); SonarQubeMonitor monitor = new SonarQubeMonitor(settings, new SecurityRealmFactory(settings), server, serverLogging); - Optional> attributes = monitor.attributes(); - assertThat(attributes.get()).containsEntry("Official Distribution", Boolean.FALSE); + Map attributes = monitor.attributes(); + assertThat(attributes).containsEntry("Official Distribution", Boolean.FALSE); } @Test public void get_log_level() throws Exception { SonarQubeMonitor monitor = new SonarQubeMonitor(settings, new SecurityRealmFactory(settings), server, serverLogging); - Optional> attributes = monitor.attributes(); - assertThat(attributes.get()).containsEntry("Logs Level", "DEBUG"); + Map attributes = monitor.attributes(); + assertThat(attributes).containsEntry("Logs Level", "DEBUG"); } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SystemMonitorTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SystemMonitorTest.java index 07510691802..e8290638a65 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SystemMonitorTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SystemMonitorTest.java @@ -35,7 +35,7 @@ public class SystemMonitorTest { @Test public void system_properties() { - Map attributes = underTest.attributes().get(); + Map attributes = underTest.attributes(); assertThat(attributes).containsKeys("System Date", "Processors"); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/InfoActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/InfoActionTest.java index 41a0a6788b9..c4a61be4f80 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/InfoActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/InfoActionTest.java @@ -19,17 +19,18 @@ */ package org.sonar.server.platform.ws; -import com.google.common.base.Optional; import java.util.LinkedHashMap; import java.util.Map; import org.junit.Rule; import org.junit.Test; +import org.mockito.Mockito; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.internal.SimpleGetRequest; import org.sonar.core.permission.GlobalPermissions; import org.sonar.server.exceptions.ForbiddenException; import org.sonar.server.platform.monitoring.Monitor; +import org.sonar.server.platform.monitoring.ProcessSystemInfoClient; import org.sonar.server.tester.UserSessionRule; import org.sonar.server.ws.WsTester; @@ -40,12 +41,12 @@ import static org.mockito.Mockito.when; public class InfoActionTest { @Rule public UserSessionRule userSessionRule = UserSessionRule.standalone().login("login") - .setName("name"); + .setName("name"); Monitor monitor1 = mock(Monitor.class); Monitor monitor2 = mock(Monitor.class); - Monitor monitor3 = mock(Monitor.class); - InfoAction underTest = new InfoAction(userSessionRule, monitor1, monitor2, monitor3); + ProcessSystemInfoClient processSystemInfoClient = mock(ProcessSystemInfoClient.class, Mockito.RETURNS_MOCKS); + InfoAction underTest = new InfoAction(userSessionRule, processSystemInfoClient, monitor1, monitor2); @Test(expected = ForbiddenException.class) public void should_fail_when_does_not_have_admin_right() { @@ -64,11 +65,9 @@ public class InfoActionTest { attributes2.put("one", 1); attributes2.put("two", 2); when(monitor1.name()).thenReturn("Monitor One"); - when(monitor1.attributes()).thenReturn(Optional.of(attributes1)); + when(monitor1.attributes()).thenReturn(attributes1); when(monitor2.name()).thenReturn("Monitor Two"); - when(monitor2.attributes()).thenReturn(Optional.of(attributes2)); - when(monitor3.name()).thenReturn("Monitor Three"); - when(monitor3.attributes()).thenReturn(Optional.>absent()); + when(monitor2.attributes()).thenReturn(attributes2); WsTester.TestResponse response = new WsTester.TestResponse(); underTest.handle(new SimpleGetRequest(), response); diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/SystemWsTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/SystemWsTest.java index 773e6d5b0a5..adda7539e6b 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/ws/SystemWsTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/SystemWsTest.java @@ -24,6 +24,7 @@ import org.sonar.api.config.Settings; import org.sonar.api.server.ws.WebService; import org.sonar.server.app.ProcessCommandWrapper; import org.sonar.server.platform.Platform; +import org.sonar.server.platform.monitoring.ProcessSystemInfoClient; import org.sonar.server.tester.AnonymousMockUserSession; import org.sonar.server.user.UserSession; @@ -32,10 +33,12 @@ import static org.mockito.Mockito.mock; public class SystemWsTest { + ProcessSystemInfoClient processSystemInfoClient = mock(ProcessSystemInfoClient.class); + @Test public void define() { RestartAction action1 = new RestartAction(mock(UserSession.class), mock(Settings.class), mock(Platform.class), mock(ProcessCommandWrapper.class)); - InfoAction action2 = new InfoAction(new AnonymousMockUserSession()); + InfoAction action2 = new InfoAction(new AnonymousMockUserSession(), processSystemInfoClient); SystemWs ws = new SystemWs(action1, action2); WebService.Context context = new WebService.Context(); diff --git a/sonar-application/assembly.xml b/sonar-application/assembly.xml index 069bd23add4..b04e3a21437 100644 --- a/sonar-application/assembly.xml +++ b/sonar-application/assembly.xml @@ -71,8 +71,8 @@ lib/ce false - false - false + true + true org.sonarsource.sonarqube:sonar-ce diff --git a/tests/upgrade/projects/struts-1.3.9-diet/core/src/main/resources/org/apache/struts/resources/web-app_2_3.dtd b/tests/upgrade/projects/struts-1.3.9-diet/core/src/main/resources/org/apache/struts/resources/web-app_2_3.dtd index b110d76de39..ba39dc9135c 100644 --- a/tests/upgrade/projects/struts-1.3.9-diet/core/src/main/resources/org/apache/struts/resources/web-app_2_3.dtd +++ b/tests/upgrade/projects/struts-1.3.9-diet/core/src/main/resources/org/apache/struts/resources/web-app_2_3.dtd @@ -71,989 +71,989 @@ TOUTE GARANTIE IMPLICITE RELATIVE A LA QUALITE MARCHANDE, A L'APTITUDE A UNE UTILISATION PARTICULIERE OU A L'ABSENCE DE CONTREFACON. --> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + - - + ejb/Payroll + --> + - - + Used in: ejb-local-ref, ejb-ref + --> + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + Example: - - - - + -Example: + - - - - - - + -Used in: web-app ---> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + -Used in: listener ---> - + - + Used in: servlet + --> + - - + --> + - - + Used in: ejb-local-ref + --> + - - + Used in: error-page + --> + - - + Used in: web-app + --> + - - + Used in: web-app + --> + - - + Used in: mime-mapping + --> + - - + Used in: context-param, init-param + --> + - - + Used in: context-param, init-param + --> + - - + Used in: login-config + --> + - - + com.wombat.empl.EmployeeService + --> + - - + Used in: resource-ref + --> + - - + Used in: resource-ref + --> + - - + Used in: resource-ref + --> + - - + Used in: resource-ref + --> + - - + jms/StockQueue + javax.jms.Queue + + --> + - - - - - - - - + + + + + + + - - + Used in: security-role-ref + --> + - + + + + + + + + + - + Used in: web-app + + Example: - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + The value of the role-name element must be the String used as the + parameter to the EJBContext.isCallerInRole(String roleName) method + or the HttpServletRequest.isUserInRole(String role) method. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + Used in: servlet + + --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 2.39.5