From b5f3b88aac1f507586983dd6b2ebbdd46b97810e Mon Sep 17 00:00:00 2001 From: Simon Brandhof Date: Tue, 19 Sep 2017 17:39:54 +0200 Subject: [PATCH] SONAR-9802 request all nodes from api/system/cluster_info --- .../container/ComputeEngineContainerImpl.java | 2 + .../ce/monitoring/CeSystemInfoModule.java | 41 +++ .../org/sonar/process/systeminfo/Global.java} | 20 +- .../systeminfo/JvmPropertiesSection.java | 4 +- .../process/systeminfo/JvmStateSection.java | 2 - .../process/systeminfo/SystemInfoUtils.java | 32 +- .../systeminfo/JvmPropertiesSectionTest.java | 19 +- .../systeminfo/JvmStateSectionTest.java | 2 +- .../systeminfo/SystemInfoUtilsTest.java | 50 +++ .../monitoring/EsStatisticsSection.java | 5 +- .../monitoring/OfficialDistribution.java | 43 +++ .../platform/monitoring/PluginsSection.java | 2 + .../platform/monitoring/SettingsSection.java | 5 +- ...tion.java => StandaloneSystemSection.java} | 22 +- .../monitoring/WebSystemInfoModule.java | 19 +- .../cluster/AppNodesInfoLoader.java} | 13 +- .../cluster/AppNodesInfoLoaderImpl.java | 86 +++++ .../monitoring/cluster/GlobalInfoLoader.java | 45 +++ .../cluster/GlobalSystemSection.java | 116 +++++++ .../platform/monitoring/cluster/NodeInfo.java | 76 ++++ .../monitoring/cluster/NodeSystemSection.java | 71 ++++ .../cluster/ProcessInfoProvider.java | 61 ++++ .../monitoring/cluster/package-info.java | 23 ++ .../server/platform/ws/ClusterInfoAction.java | 327 +++++++++++------- .../sonar/server/platform/ws/InfoAction.java | 23 +- .../monitoring/OfficialDistributionTest.java | 59 ++++ ....java => StandaloneSystemSectionTest.java} | 28 +- .../monitoring/cluster/NodeInfoTest.java | 42 +++ 28 files changed, 1031 insertions(+), 207 deletions(-) create mode 100644 server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeSystemInfoModule.java rename server/{sonar-server/src/main/java/org/sonar/server/platform/ws/InfoActionModule.java => sonar-process/src/main/java/org/sonar/process/systeminfo/Global.java} (70%) create mode 100644 server/sonar-process/src/test/java/org/sonar/process/systeminfo/SystemInfoUtilsTest.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/OfficialDistribution.java rename server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/{SystemSection.java => StandaloneSystemSection.java} (87%) rename server/sonar-server/src/main/java/org/sonar/server/{telemetry/TelemetryModule.java => platform/monitoring/cluster/AppNodesInfoLoader.java} (78%) create mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/AppNodesInfoLoaderImpl.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/GlobalInfoLoader.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/GlobalSystemSection.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/NodeInfo.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/NodeSystemSection.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/ProcessInfoProvider.java create mode 100644 server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/package-info.java create mode 100644 server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/OfficialDistributionTest.java rename server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/{SystemSectionTest.java => StandaloneSystemSectionTest.java} (91%) create mode 100644 server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/NodeInfoTest.java 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 b443c7f6894..79f042caf3d 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 @@ -49,6 +49,7 @@ import org.sonar.ce.StandaloneCeDistributedInformation; import org.sonar.ce.cleaning.CeCleaningModule; import org.sonar.ce.db.ReadOnlyPropertiesDao; import org.sonar.ce.log.CeProcessLogging; +import org.sonar.ce.monitoring.CeSystemInfoModule; import org.sonar.ce.platform.ComputeEngineExtensionInstaller; import org.sonar.ce.queue.CeQueueCleaner; import org.sonar.ce.queue.PurgeCeActivities; @@ -423,6 +424,7 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer { container.add( StartableHazelcastMember.class, CeDistributedInformationImpl.class); + container.add(CeSystemInfoModule.forClusterMode()); } else { container.add(StandaloneCeDistributedInformation.class); } diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeSystemInfoModule.java b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeSystemInfoModule.java new file mode 100644 index 00000000000..be53383ebee --- /dev/null +++ b/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeSystemInfoModule.java @@ -0,0 +1,41 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.ce.monitoring; + +import org.sonar.process.systeminfo.JvmPropertiesSection; +import org.sonar.process.systeminfo.JvmStateSection; +import org.sonar.server.platform.monitoring.DatabaseSection; +import org.sonar.server.platform.monitoring.cluster.ProcessInfoProvider; + +public class CeSystemInfoModule { + + private CeSystemInfoModule() { + // do not instantiate + } + + public static Object[] forClusterMode() { + return new Object[] { + new JvmPropertiesSection("Compute Engine JVM Properties"), + new JvmStateSection("Compute Engine JVM State"), + DatabaseSection.class, + ProcessInfoProvider.class + }; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/InfoActionModule.java b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/Global.java similarity index 70% rename from server/sonar-server/src/main/java/org/sonar/server/platform/ws/InfoActionModule.java rename to server/sonar-process/src/main/java/org/sonar/process/systeminfo/Global.java index fb3f3859a2d..83e9568b832 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/InfoActionModule.java +++ b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/Global.java @@ -17,17 +17,13 @@ * 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.ws; +package org.sonar.process.systeminfo; -import org.sonar.core.platform.Module; -import org.sonar.server.telemetry.TelemetryDataLoader; - -public class InfoActionModule extends Module { - @Override - protected void configureModule() { - add(TelemetryDataLoader.class, - InfoAction.class, - ClusterInfoAction.class, - StandaloneInfoAction.class); - } +/** + * Interface to mark {@link SystemInfoSection} of web server as global. + * In case of cluster mode, all the processes and nodes would return + * the same values, so it's loaded once on the web server that receives + * the user request. + */ +public interface Global { } diff --git a/server/sonar-process/src/main/java/org/sonar/process/systeminfo/JvmPropertiesSection.java b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/JvmPropertiesSection.java index 8b0a31b0065..1cb014bde4f 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/systeminfo/JvmPropertiesSection.java +++ b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/JvmPropertiesSection.java @@ -21,6 +21,7 @@ package org.sonar.process.systeminfo; import java.util.Map; import java.util.Objects; +import java.util.TreeMap; import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute; @@ -41,7 +42,8 @@ public class JvmPropertiesSection implements SystemInfoSection { ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder(); protobuf.setName(name); - for (Map.Entry systemProp : System.getProperties().entrySet()) { + Map sortedProperties = new TreeMap<>(System.getProperties()); + for (Map.Entry systemProp : sortedProperties.entrySet()) { if (systemProp.getValue() != null) { setAttribute(protobuf, Objects.toString(systemProp.getKey()), Objects.toString(systemProp.getValue())); } diff --git a/server/sonar-process/src/main/java/org/sonar/process/systeminfo/JvmStateSection.java b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/JvmStateSection.java index 656fba7e75b..804e2f0de5e 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/systeminfo/JvmStateSection.java +++ b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/JvmStateSection.java @@ -61,8 +61,6 @@ public class JvmStateSection implements SystemInfoSection { ThreadMXBean thread = ManagementFactory.getThreadMXBean(); setAttribute(protobuf, "Threads", thread.getThreadCount()); - setAttribute(protobuf,"Processors", Runtime.getRuntime().availableProcessors()); - return protobuf.build(); } diff --git a/server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoUtils.java b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoUtils.java index 63dbdec055d..0126bbe2ae7 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoUtils.java +++ b/server/sonar-process/src/main/java/org/sonar/process/systeminfo/SystemInfoUtils.java @@ -19,10 +19,17 @@ */ package org.sonar.process.systeminfo; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo.Section; + +import static java.util.Arrays.stream; public class SystemInfoUtils { @@ -30,7 +37,7 @@ public class SystemInfoUtils { // prevent instantiation } - public static void setAttribute(ProtobufSystemInfo.Section.Builder section, String key, @Nullable String value) { + public static void setAttribute(Section.Builder section, String key, @Nullable String value) { if (value != null) { section.addAttributesBuilder() .setKey(key) @@ -39,7 +46,7 @@ public class SystemInfoUtils { } } - public static void setAttribute(ProtobufSystemInfo.Section.Builder section, String key, @Nullable Collection values) { + public static void setAttribute(Section.Builder section, String key, @Nullable Collection values) { if (values != null) { section.addAttributesBuilder() .setKey(key) @@ -48,14 +55,14 @@ public class SystemInfoUtils { } } - public static void setAttribute(ProtobufSystemInfo.Section.Builder section, String key, boolean value) { + public static void setAttribute(Section.Builder section, String key, boolean value) { section.addAttributesBuilder() .setKey(key) .setBooleanValue(value) .build(); } - public static void setAttribute(ProtobufSystemInfo.Section.Builder section, String key, long value) { + public static void setAttribute(Section.Builder section, String key, long value) { section.addAttributesBuilder() .setKey(key) .setLongValue(value) @@ -63,7 +70,7 @@ public class SystemInfoUtils { } @CheckForNull - public static ProtobufSystemInfo.Attribute attribute(ProtobufSystemInfo.Section section, String key) { + public static ProtobufSystemInfo.Attribute attribute(Section section, String key) { for (ProtobufSystemInfo.Attribute attribute : section.getAttributesList()) { if (attribute.getKey().equals(key)) { return attribute; @@ -71,4 +78,19 @@ public class SystemInfoUtils { } return null; } + + public static List
order(Collection
sections, String... orderedNames) { + Map alphabeticalOrderedMap = new TreeMap<>(); + sections.forEach(section -> alphabeticalOrderedMap.put(section.getName(), section)); + + List
result = new ArrayList<>(sections.size()); + stream(orderedNames).forEach(name -> { + Section section = alphabeticalOrderedMap.remove(name); + if (section != null) { + result.add(section); + } + }); + result.addAll(alphabeticalOrderedMap.values()); + return result; + } } diff --git a/server/sonar-process/src/test/java/org/sonar/process/systeminfo/JvmPropertiesSectionTest.java b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/JvmPropertiesSectionTest.java index dcf4cb9893c..2050e0a3f73 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/systeminfo/JvmPropertiesSectionTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/JvmPropertiesSectionTest.java @@ -19,12 +19,14 @@ */ package org.sonar.process.systeminfo; -import org.assertj.core.api.Assertions; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; import org.junit.Test; import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.process.systeminfo.SystemInfoUtils.attribute; public class JvmPropertiesSectionTest { @@ -36,10 +38,17 @@ public class JvmPropertiesSectionTest { } @Test - public void test_toProtobuf() { + public void system_properties_are_returned_in_alphabetical_order() { ProtobufSystemInfo.Section section = underTest.toProtobuf(); - Assertions.assertThat(attribute(section, "java.vm.vendor").getStringValue()).isNotEmpty(); - Assertions.assertThat(attribute(section, "os.name").getStringValue()).isNotEmpty(); + List keys = section.getAttributesList() + .stream() + .map(ProtobufSystemInfo.Attribute::getKey) + .collect(Collectors.toList()); + assertThat(keys).contains("java.vm.vendor", "os.name"); + + List sortedKeys = new ArrayList<>(keys); + Collections.sort(sortedKeys); + assertThat(sortedKeys).isEqualTo(keys); } } diff --git a/server/sonar-process/src/test/java/org/sonar/process/systeminfo/JvmStateSectionTest.java b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/JvmStateSectionTest.java index 3057e9933e9..77da5df5719 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/systeminfo/JvmStateSectionTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/JvmStateSectionTest.java @@ -39,7 +39,7 @@ public class JvmStateSectionTest { assertThat(section.getName()).isEqualTo(PROCESS_NAME); assertThat(section.getAttributesCount()).isGreaterThan(0); - assertThat(section.getAttributesList()).extracting("key").contains("Threads", "Processors"); + assertThat(section.getAttributesList()).extracting("key").contains("Threads", "Heap Max (MB)"); } @Test diff --git a/server/sonar-process/src/test/java/org/sonar/process/systeminfo/SystemInfoUtilsTest.java b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/SystemInfoUtilsTest.java new file mode 100644 index 00000000000..03410f34ea9 --- /dev/null +++ b/server/sonar-process/src/test/java/org/sonar/process/systeminfo/SystemInfoUtilsTest.java @@ -0,0 +1,50 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.util.Collection; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.Test; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo.Section; + +import static java.util.Arrays.asList; +import static org.assertj.core.api.Assertions.assertThat; + +public class SystemInfoUtilsTest { + + @Test + public void test_order() { + Collection
sections = asList( + newSection("end2"), + newSection("bar"), + newSection("end1"), + newSection("foo")); + + List ordered = SystemInfoUtils.order(sections, "foo", "bar").stream() + .map(Section::getName) + .collect(Collectors.toList()); + assertThat(ordered).isEqualTo(asList("foo", "bar", "end1", "end2")); + } + + private static Section newSection(String name) { + return Section.newBuilder().setName(name).build(); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStatisticsSection.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStatisticsSection.java index 12656ae4f3e..c317854fc6f 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStatisticsSection.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStatisticsSection.java @@ -23,7 +23,9 @@ import java.util.Map; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.admin.indices.stats.IndexStats; import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; +import org.sonar.api.server.ServerSide; import org.sonar.api.utils.log.Loggers; +import org.sonar.process.systeminfo.Global; import org.sonar.process.systeminfo.SystemInfoSection; import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; import org.sonar.server.es.EsClient; @@ -31,7 +33,8 @@ import org.sonar.server.es.EsClient; import static org.apache.commons.io.FileUtils.byteCountToDisplaySize; import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute; -public class EsStatisticsSection implements SystemInfoSection { +@ServerSide +public class EsStatisticsSection implements SystemInfoSection, Global { private final EsClient esClient; diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/OfficialDistribution.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/OfficialDistribution.java new file mode 100644 index 00000000000..4120fcda0f4 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/OfficialDistribution.java @@ -0,0 +1,43 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.sonar.api.platform.Server; +import org.sonar.api.server.ServerSide; + +@ServerSide +public class OfficialDistribution { + static final String BRANDING_FILE_PATH = "web/WEB-INF/classes/com/sonarsource/branding"; + + private final Server server; + + public OfficialDistribution(Server server) { + this.server = server; + } + + public boolean check() { + // the dependency com.sonarsource:sonarsource-branding is shaded to webapp + // during release (see sonar-web pom) + File brandingFile = new File(server.getRootDir(), BRANDING_FILE_PATH); + // no need to check that the file exists. java.io.File#length() returns zero in this case. + return brandingFile.length() > 0L; + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/PluginsSection.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/PluginsSection.java index 491a8bf1265..15508a91fd9 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/PluginsSection.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/PluginsSection.java @@ -19,6 +19,7 @@ */ package org.sonar.server.platform.monitoring; +import org.sonar.api.server.ServerSide; import org.sonar.core.platform.PluginInfo; import org.sonar.core.platform.PluginRepository; import org.sonar.process.systeminfo.SystemInfoSection; @@ -27,6 +28,7 @@ import org.sonar.updatecenter.common.Version; import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute; +@ServerSide public class PluginsSection implements SystemInfoSection { private final PluginRepository repository; diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SettingsSection.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SettingsSection.java index 12f1d688623..e6e3a473635 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SettingsSection.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SettingsSection.java @@ -24,13 +24,16 @@ import org.sonar.api.PropertyType; import org.sonar.api.config.PropertyDefinition; import org.sonar.api.config.PropertyDefinitions; import org.sonar.api.config.Settings; +import org.sonar.api.server.ServerSide; +import org.sonar.process.systeminfo.Global; import org.sonar.process.systeminfo.SystemInfoSection; import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; import static org.apache.commons.lang.StringUtils.abbreviate; import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute; -public class SettingsSection implements SystemInfoSection { +@ServerSide +public class SettingsSection implements SystemInfoSection, Global { static final int MAX_VALUE_LENGTH = 500; private final Settings settings; diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SystemSection.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/StandaloneSystemSection.java similarity index 87% rename from server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SystemSection.java rename to server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/StandaloneSystemSection.java index d19f7162ae4..acdffa2efb5 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/SystemSection.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/StandaloneSystemSection.java @@ -20,7 +20,6 @@ package org.sonar.server.platform.monitoring; import com.google.common.base.Joiner; -import java.io.File; import java.util.List; import javax.annotation.CheckForNull; import javax.annotation.Nullable; @@ -41,29 +40,29 @@ import org.sonar.server.user.SecurityRealmFactory; import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute; -public class SystemSection extends BaseSectionMBean implements SystemSectionMBean { +public class StandaloneSystemSection extends BaseSectionMBean implements SystemSectionMBean { private static final Joiner COMMA_JOINER = Joiner.on(", "); - static final String BRANDING_FILE_PATH = "web/WEB-INF/classes/com/sonarsource/branding"; - private final Configuration config; private final SecurityRealmFactory securityRealmFactory; private final IdentityProviderRepository identityProviderRepository; private final Server server; private final ServerLogging serverLogging; private final ServerIdLoader serverIdLoader; + private final OfficialDistribution officialDistribution; private final HealthChecker healthChecker; - public SystemSection(Configuration config, SecurityRealmFactory securityRealmFactory, + public StandaloneSystemSection(Configuration config, SecurityRealmFactory securityRealmFactory, IdentityProviderRepository identityProviderRepository, Server server, ServerLogging serverLogging, - ServerIdLoader serverIdLoader, HealthChecker healthChecker) { + ServerIdLoader serverIdLoader, OfficialDistribution officialDistribution, HealthChecker healthChecker) { this.config = config; this.securityRealmFactory = securityRealmFactory; this.identityProviderRepository = identityProviderRepository; this.server = server; this.serverLogging = serverLogging; this.serverIdLoader = serverIdLoader; + this.officialDistribution = officialDistribution; this.healthChecker = healthChecker; } @@ -109,14 +108,6 @@ public class SystemSection extends BaseSectionMBean implements SystemSectionMBea return config.getBoolean(CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY).orElse(false); } - private boolean isOfficialDistribution() { - // the dependency com.sonarsource:sonarsource-branding is shaded to webapp - // during release (see sonar-web pom) - File brandingFile = new File(server.getRootDir(), BRANDING_FILE_PATH); - // no need to check that the file exists. java.io.File#length() returns zero in this case. - return brandingFile.length() > 0L; - } - @Override public String name() { // JMX name @@ -140,13 +131,14 @@ public class SystemSection extends BaseSectionMBean implements SystemSectionMBea addIfNotEmpty(protobuf, "Accepted external identity providers", getEnabledIdentityProviders()); addIfNotEmpty(protobuf, "External identity providers whose users are allowed to sign themselves up", getAllowsToSignUpEnabledIdentityProviders()); setAttribute(protobuf, "High Availability", false); - setAttribute(protobuf, "Official Distribution", isOfficialDistribution()); + setAttribute(protobuf, "Official Distribution", officialDistribution.check()); setAttribute(protobuf, "Force authentication", getForceAuthentication()); setAttribute(protobuf, "Home Dir", config.get(ProcessProperties.PATH_HOME).orElse(null)); setAttribute(protobuf, "Data Dir", config.get(ProcessProperties.PATH_DATA).orElse(null)); setAttribute(protobuf, "Temp Dir", config.get(ProcessProperties.PATH_TEMP).orElse(null)); setAttribute(protobuf, "Logs Dir", config.get(ProcessProperties.PATH_LOGS).orElse(null)); setAttribute(protobuf, "Logs Level", getLogLevel()); + setAttribute(protobuf, "Processors", Runtime.getRuntime().availableProcessors()); return protobuf.build(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/WebSystemInfoModule.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/WebSystemInfoModule.java index 09c40749fc8..b5f495f2c64 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/WebSystemInfoModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/WebSystemInfoModule.java @@ -21,6 +21,11 @@ package org.sonar.server.platform.monitoring; import org.sonar.process.systeminfo.JvmPropertiesSection; import org.sonar.process.systeminfo.JvmStateSection; +import org.sonar.server.platform.monitoring.cluster.AppNodesInfoLoaderImpl; +import org.sonar.server.platform.monitoring.cluster.GlobalInfoLoader; +import org.sonar.server.platform.monitoring.cluster.GlobalSystemSection; +import org.sonar.server.platform.monitoring.cluster.ProcessInfoProvider; +import org.sonar.server.platform.monitoring.cluster.NodeSystemSection; import org.sonar.server.platform.ws.ClusterInfoAction; import org.sonar.server.platform.ws.StandaloneInfoAction; @@ -39,7 +44,9 @@ public class WebSystemInfoModule { EsStatisticsSection.class, PluginsSection.class, SettingsSection.class, - SystemSection.class, + StandaloneSystemSection.class, + + OfficialDistribution.class, StandaloneInfoAction.class }; @@ -50,9 +57,17 @@ public class WebSystemInfoModule { new JvmPropertiesSection("Web JVM Properties"), new JvmStateSection("Web JVM State"), DatabaseSection.class, - EsStateSection.class, + EsStatisticsSection.class, + GlobalSystemSection.class, + NodeSystemSection.class, PluginsSection.class, + SettingsSection.class, + + OfficialDistribution.class, + ProcessInfoProvider.class, + GlobalInfoLoader.class, + AppNodesInfoLoaderImpl.class, ClusterInfoAction.class }; } diff --git a/server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryModule.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/AppNodesInfoLoader.java similarity index 78% rename from server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryModule.java rename to server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/AppNodesInfoLoader.java index 447f11e5a0e..f3ffd959865 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/telemetry/TelemetryModule.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/AppNodesInfoLoader.java @@ -17,14 +17,11 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.server.telemetry; +package org.sonar.server.platform.monitoring.cluster; -import org.sonar.core.platform.Module; +import java.util.Collection; -public class TelemetryModule extends Module { - @Override - protected void configureModule() { - add(TelemetryDaemon.class, - TelemetryClient.class); - } +public interface AppNodesInfoLoader { + + Collection load(); } diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/AppNodesInfoLoaderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/AppNodesInfoLoaderImpl.java new file mode 100644 index 00000000000..03eaaa09dfe --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/AppNodesInfoLoaderImpl.java @@ -0,0 +1,86 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.cluster; + +import com.hazelcast.core.Member; +import com.hazelcast.core.MemberSelector; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import org.sonar.api.server.ServerSide; +import org.sonar.process.ProcessId; +import org.sonar.process.cluster.hz.DistributedAnswer; +import org.sonar.process.cluster.hz.HazelcastMember; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +@ServerSide +public class AppNodesInfoLoaderImpl implements AppNodesInfoLoader { + + private final HazelcastMember hzMember; + + public AppNodesInfoLoaderImpl(HazelcastMember hzMember) { + this.hzMember = hzMember; + } + + public Collection load() { + try { + Map nodesByName = new HashMap<>(); + DistributedAnswer distributedAnswer = hzMember.call(ProcessInfoProvider::provide, new CeWebMemberSelector(), 15_000L); + for (Member member : distributedAnswer.getMembers()) { + String nodeName = member.getStringAttribute(HazelcastMember.Attribute.NODE_NAME); + NodeInfo nodeInfo = nodesByName.get(nodeName); + if (nodeInfo == null) { + nodeInfo = new NodeInfo(nodeName); + nodesByName.put(nodeName, nodeInfo); + + String hostname = member.getStringAttribute(HazelcastMember.Attribute.HOSTNAME); + nodeInfo.setAttribute("Hostname", hostname); + } + completeNodeInfo(distributedAnswer, member, nodeInfo); + } + return nodesByName.values(); + + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new IllegalStateException(e); + } + } + + private void completeNodeInfo(DistributedAnswer distributedAnswer, Member member, NodeInfo nodeInfo) { + Optional nodeAnswer = distributedAnswer.getAnswer(member); + Optional failure = distributedAnswer.getFailed(member); + if (distributedAnswer.hasTimedOut(member)) { + nodeInfo.setAttribute("Error", "Failed to retrieve information on time"); + } else if (failure.isPresent()) { + nodeInfo.setAttribute("Error", "Failed to retrieve information: " + failure.get().getMessage()); + } else if (nodeAnswer.isPresent()) { + nodeAnswer.get().getSectionsList().forEach(nodeInfo::addSection); + } + } + + private static class CeWebMemberSelector implements MemberSelector { + @Override + public boolean select(Member member) { + String processKey = member.getStringAttribute(HazelcastMember.Attribute.PROCESS_KEY); + return processKey.equals(ProcessId.WEB_SERVER.getKey()) || processKey.equals(ProcessId.COMPUTE_ENGINE.getKey()); + } + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/GlobalInfoLoader.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/GlobalInfoLoader.java new file mode 100644 index 00000000000..f9c01d389ee --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/GlobalInfoLoader.java @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.cluster; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.sonar.api.server.ServerSide; +import org.sonar.process.systeminfo.Global; +import org.sonar.process.systeminfo.SystemInfoSection; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +@ServerSide +public class GlobalInfoLoader { + private final List globalSections; + + public GlobalInfoLoader(SystemInfoSection[] sections) { + this.globalSections = Arrays.stream(sections) + .filter(section -> section instanceof Global) + .collect(Collectors.toList()); + } + + public List load() { + return globalSections.stream() + .map(SystemInfoSection::toProtobuf) + .collect(Collectors.toList()); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/GlobalSystemSection.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/GlobalSystemSection.java new file mode 100644 index 00000000000..90875c5d7b6 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/GlobalSystemSection.java @@ -0,0 +1,116 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.cluster; + +import com.google.common.base.Joiner; +import java.util.List; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; +import org.sonar.api.CoreProperties; +import org.sonar.api.config.Configuration; +import org.sonar.api.security.SecurityRealm; +import org.sonar.api.server.ServerSide; +import org.sonar.api.server.authentication.IdentityProvider; +import org.sonar.core.util.stream.MoreCollectors; +import org.sonar.process.systeminfo.Global; +import org.sonar.process.systeminfo.SystemInfoSection; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; +import org.sonar.server.authentication.IdentityProviderRepository; +import org.sonar.server.health.ClusterHealth; +import org.sonar.server.health.HealthChecker; +import org.sonar.server.platform.ServerIdLoader; +import org.sonar.server.user.SecurityRealmFactory; + +import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute; + +@ServerSide +public class GlobalSystemSection implements SystemInfoSection, Global { + private static final Joiner COMMA_JOINER = Joiner.on(", "); + + private final Configuration config; + private final ServerIdLoader serverIdLoader; + private final SecurityRealmFactory securityRealmFactory; + private final IdentityProviderRepository identityProviderRepository; + private final HealthChecker healthChecker; + + public GlobalSystemSection(Configuration config, ServerIdLoader serverIdLoader, SecurityRealmFactory securityRealmFactory, + IdentityProviderRepository identityProviderRepository, HealthChecker healthChecker) { + this.config = config; + this.serverIdLoader = serverIdLoader; + this.securityRealmFactory = securityRealmFactory; + this.identityProviderRepository = identityProviderRepository; + this.healthChecker = healthChecker; + } + + @Override + public ProtobufSystemInfo.Section toProtobuf() { + ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder(); + protobuf.setName("System"); + + ClusterHealth health = healthChecker.checkCluster(); + + setAttribute(protobuf, "Health", health.getHealth().getStatus().name()); + setAttribute(protobuf, "Health Causes", health.getHealth().getCauses()); + serverIdLoader.get().ifPresent(serverId -> { + setAttribute(protobuf, "Server ID", serverId.getId()); + setAttribute(protobuf, "Server ID validated", serverId.isValid()); + }); + setAttribute(protobuf, "High Availability", true); + setAttribute(protobuf, "External User Authentication", getExternalUserAuthentication()); + addIfNotEmpty(protobuf, "Accepted external identity providers", getEnabledIdentityProviders()); + addIfNotEmpty(protobuf, "External identity providers whose users are allowed to sign themselves up", getAllowsToSignUpEnabledIdentityProviders()); + setAttribute(protobuf, "Force authentication", getForceAuthentication()); + return protobuf.build(); + } + + private List getEnabledIdentityProviders() { + return identityProviderRepository.getAllEnabledAndSorted() + .stream() + .filter(IdentityProvider::isEnabled) + .map(IdentityProvider::getName) + .collect(MoreCollectors.toList()); + } + + private List getAllowsToSignUpEnabledIdentityProviders() { + return identityProviderRepository.getAllEnabledAndSorted() + .stream() + .filter(IdentityProvider::isEnabled) + .filter(IdentityProvider::allowsUsersToSignUp) + .map(IdentityProvider::getName) + .collect(MoreCollectors.toList()); + } + + private boolean getForceAuthentication() { + return config.getBoolean(CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY).orElse(false); + } + + private static void addIfNotEmpty(ProtobufSystemInfo.Section.Builder protobuf, String key, @Nullable List values) { + if (values != null && !values.isEmpty()) { + setAttribute(protobuf, key, COMMA_JOINER.join(values)); + } + } + + @CheckForNull + private String getExternalUserAuthentication() { + SecurityRealm realm = securityRealmFactory.getRealm(); + return realm == null ? null : realm.getName(); + } + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/NodeInfo.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/NodeInfo.java new file mode 100644 index 00000000000..3a53e1b829c --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/NodeInfo.java @@ -0,0 +1,76 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.cluster; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +public class NodeInfo { + + private final String name; + private final Map attributes = new LinkedHashMap<>(); + private final List sections = new ArrayList<>(); + + public NodeInfo(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public NodeInfo setAttribute(String key, String value) { + this.attributes.put(key, value); + return this; + } + + public Map getAttributes() { + return attributes; + } + + public NodeInfo addSection(ProtobufSystemInfo.Section section) { + this.sections.add(section); + return this; + } + + public List getSections() { + return sections; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + NodeInfo nodeInfo = (NodeInfo) o; + return name.equals(nodeInfo.name); + } + + @Override + public int hashCode() { + return name.hashCode(); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/NodeSystemSection.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/NodeSystemSection.java new file mode 100644 index 00000000000..8ab8a07f1e2 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/NodeSystemSection.java @@ -0,0 +1,71 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.cluster; + +import org.sonar.api.config.Configuration; +import org.sonar.api.platform.Server; +import org.sonar.api.server.ServerSide; +import org.sonar.process.ProcessProperties; +import org.sonar.process.systeminfo.SystemInfoSection; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; +import org.sonar.server.health.Health; +import org.sonar.server.health.HealthChecker; +import org.sonar.server.platform.ServerLogging; +import org.sonar.server.platform.monitoring.OfficialDistribution; + +import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute; + +@ServerSide +public class NodeSystemSection implements SystemInfoSection { + + private final Configuration config; + private final Server server; + private final ServerLogging serverLogging; + private final OfficialDistribution officialDistribution; + private final HealthChecker healthChecker; + + public NodeSystemSection(Configuration config, Server server, ServerLogging serverLogging, + OfficialDistribution officialDistribution, HealthChecker healthChecker) { + this.config = config; + this.server = server; + this.serverLogging = serverLogging; + this.officialDistribution = officialDistribution; + this.healthChecker = healthChecker; + } + + @Override + public ProtobufSystemInfo.Section toProtobuf() { + ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder(); + protobuf.setName("System"); + + Health health = healthChecker.checkNode(); + setAttribute(protobuf, "Health", health.getStatus().name()); + setAttribute(protobuf, "Health Causes", health.getCauses()); + setAttribute(protobuf, "Version", server.getVersion()); + setAttribute(protobuf, "Official Distribution", officialDistribution.check()); + setAttribute(protobuf, "Home Dir", config.get(ProcessProperties.PATH_HOME).orElse(null)); + setAttribute(protobuf, "Data Dir", config.get(ProcessProperties.PATH_DATA).orElse(null)); + setAttribute(protobuf, "Temp Dir", config.get(ProcessProperties.PATH_TEMP).orElse(null)); + setAttribute(protobuf, "Logs Dir", config.get(ProcessProperties.PATH_LOGS).orElse(null)); + setAttribute(protobuf, "Logs Level", serverLogging.getRootLoggerLevel().name()); + return protobuf.build(); + } + +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/ProcessInfoProvider.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/ProcessInfoProvider.java new file mode 100644 index 00000000000..3f4350c6619 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/ProcessInfoProvider.java @@ -0,0 +1,61 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.cluster; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; +import org.sonar.api.Startable; +import org.sonar.api.ce.ComputeEngineSide; +import org.sonar.api.server.ServerSide; +import org.sonar.process.systeminfo.Global; +import org.sonar.process.systeminfo.SystemInfoSection; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; + +@ServerSide +@ComputeEngineSide +public class ProcessInfoProvider implements Startable { + + /** Used for Hazelcast's distributed queries in cluster mode */ + private static ProcessInfoProvider INSTANCE; + private final List sections; + + public ProcessInfoProvider(SystemInfoSection[] sections) { + this.sections = Arrays.stream(sections) + .filter(section -> !(section instanceof Global)) + .collect(Collectors.toList()); + } + + @Override + public void start() { + INSTANCE = this; + } + + @Override + public void stop() { + INSTANCE = null; + } + + public static ProtobufSystemInfo.SystemInfo provide() { + ProtobufSystemInfo.SystemInfo.Builder protobuf = ProtobufSystemInfo.SystemInfo.newBuilder(); + INSTANCE.sections.forEach(section -> protobuf.addSections(section.toProtobuf())); + return protobuf.build(); + } +} diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/package-info.java new file mode 100644 index 00000000000..ef39a628cb6 --- /dev/null +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/package-info.java @@ -0,0 +1,23 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.server.platform.monitoring.cluster; + +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/ClusterInfoAction.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/ClusterInfoAction.java index d298d99c03a..87264373367 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/ClusterInfoAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/ClusterInfoAction.java @@ -19,19 +19,27 @@ */ package org.sonar.server.platform.ws; -import java.util.Arrays; +import java.util.Collection; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.text.JsonWriter; +import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; +import org.sonar.server.platform.monitoring.cluster.AppNodesInfoLoader; +import org.sonar.server.platform.monitoring.cluster.GlobalInfoLoader; +import org.sonar.server.platform.monitoring.cluster.NodeInfo; import org.sonar.server.user.UserSession; public class ClusterInfoAction implements SystemWsAction { private final UserSession userSession; + private final GlobalInfoLoader globalInfoLoader; + private final AppNodesInfoLoader appNodesInfoLoader; - public ClusterInfoAction(UserSession userSession) { + public ClusterInfoAction(UserSession userSession, GlobalInfoLoader globalInfoLoader, AppNodesInfoLoader appNodesInfoLoader) { this.userSession = userSession; + this.globalInfoLoader = globalInfoLoader; + this.appNodesInfoLoader = appNodesInfoLoader; } @Override @@ -50,143 +58,200 @@ public class ClusterInfoAction implements SystemWsAction { try (JsonWriter json = response.newJsonWriter()) { json.beginObject(); - - json.name("System"); - json.beginObject(); - json.prop("High Availability", true); - json.prop("Cluster Name", "fooo"); - json.prop("Server Id", "ABC123"); - json.prop("Health", "RED"); - json - .name("Health Causes") - .beginArray().values(Arrays.asList("foo", "bar")).endArray(); - json.endObject(); - - json.name("Settings"); - json.beginObject(); - json.prop("sonar.forceAuthentication", true); - json.prop("sonar.externalIdentityProviders", "GitHub, BitBucket"); + writeGlobal(json); + writeApplicationNodes(json); json.endObject(); + } - json.name("Database"); - json - .beginObject() - .prop("Name", "PostgreSQL") - .prop("Version", "9.6.3") - .endObject(); - - json.name("Compute Engine"); - json - .beginObject() - .prop("Pending", 5) - .prop("In Progress", 4) - .prop("workers", 8) - .prop("workersPerNode", 4) - .endObject(); - - json.name("Search"); - json - .beginObject() - .prop("Health", "GREEN") - .prop("Number of Nodes", 4) - .prop("Index Components - Docs", 152_515_155) - .prop("Index Components - Shards", 20) - .prop("Index Components - Size", "25GB") - .prop("Index Issues - Docs", 5) - .prop("Index Issues - Shards", 5) - .prop("Index Issues - Size", "52MB") - .prop("Index Tests - Docs", 56605) - .prop("Index Tests - Shards", 2) - .prop("Index Tests - Size", "520MB") - .endObject(); - - json.name("Application Nodes"); - json - .beginArray() - .beginObject() - .prop("Name", "Mont Blanc") - .prop("Host", "10.158.92.16") - .prop("Health", "YELLOW") - .name("healthCauses").beginArray().beginObject().prop("message", "Db connectivity error").endObject().endArray() - .prop("Start Time", "2017-05-30T10:23:45") - .prop("Official Distribution", true) - .prop("Processors", 4); - json - .name("Web JVM").beginObject() - .prop("JVM Name", "Java HotSpot(TM) 64-Bit Server VM") - .prop("JVM Vendor", "Oracle Corporation") - .prop("Max Memory", "948MB") - .prop("Free Memory", "38MB") - .endObject() - - .name("Web JVM Properties").beginObject() - .prop("catalina.home", "/sonarsource/var/tmp/sonarsource/sssonarqube/tc") - .prop("glowroot.tmp.dir", "/var/tmp/sonarsource/ssglowroot-agent") - .prop("glowroot.adad.dir", "/var/tmp/sonarsource/ssglowroot-agent") - .prop("java.specification.version", "1.8") - .endObject() - - .name("Web Database Connectivity").beginObject() - .prop("Driver", "PostgreSQL JDBC Driver") - .prop("Driver Version", "PostgreSQL JDBC Driver") - .prop("Pool Idle Connections", 2) - .prop("Pool Max Connections", 50) - .prop("URL", "jdbc:postgresql://next-rds.cn6pfc2xc6oq.us-east-1.rds.amazonaws.com/dory") - .endObject(); - - json - .name("Compute Engine JVM").beginObject() - .prop("JVM Name", "Java HotSpot(TM) 64-Bit Server VM") - .prop("JVM Vendor", "Oracle Corporation") - .prop("Max Memory", "25MB") - .prop("Free Memory", "8MB") - .endObject(); - - json - .name("Compute Engine JVM Properties").beginObject() - .prop("java.ext.dirs", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") - .prop("java.io.tmpdir", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") - .prop("java.library.path", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") - .prop("java.net.preferIPv4Stack", true) - .prop("java.rmi.server.randomIDs", true) - .prop("java.specification.version", "1.8") - .endObject(); +// try (JsonWriter json = response.newJsonWriter()) { +// json.beginObject(); +// +// // global section +// json.prop("Cluster", true); +// json.prop("Cluster Name", "foo"); +// json.prop("Server Id", "ABC123"); +// json.prop("Health", "RED"); +// json +// .name("Health Causes") +// .beginArray().beginObject().prop("message", "Requires at least two search nodes").endObject().endArray(); +// +// json.name("Settings"); +// json.beginObject(); +// json.prop("sonar.forceAuthentication", true); +// json.prop("sonar.externalIdentityProviders", "GitHub, BitBucket"); +// json.endObject(); +// +// json.name("Database"); +// json +// .beginObject() +// .prop("Name", "PostgreSQL") +// .prop("Version", "9.6.3") +// .endObject(); +// +// json.name("Compute Engine"); +// json +// .beginObject() +// .prop("Pending", 5) +// .prop("In Progress", 4) +// .prop("workers", 8) +// .prop("workersPerNode", 4) +// .endObject(); +// +// json.name("Elasticsearch"); +// json +// .beginObject() +// .prop("Health", "GREEN") +// .prop("Number of Nodes", 4) +// .prop("Index Components - Docs", 152_515_155) +// .prop("Index Components - Shards", 20) +// .prop("Index Components - Size", "25GB") +// .prop("Index Issues - Docs", 5) +// .prop("Index Issues - Shards", 5) +// .prop("Index Issues - Size", "52MB") +// .prop("Index Tests - Docs", 56605) +// .prop("Index Tests - Shards", 2) +// .prop("Index Tests - Size", "520MB") +// .endObject(); +// +// json.name("Application Nodes"); +// json +// .beginArray() +// .beginObject() +// .prop("Name", "Mont Blanc") +// .prop("Host", "10.158.92.16") +// .prop("Health", "YELLOW") +// .name("healthCauses").beginArray().beginObject().prop("message", "Db connectivity error").endObject().endArray() +// .prop("Start Time", "2017-05-30T10:23:45") +// .prop("Official Distribution", true) +// .prop("Processors", 4); +// json +// .name("Web JVM").beginObject() +// .prop("JVM Name", "Java HotSpot(TM) 64-Bit Server VM") +// .prop("JVM Vendor", "Oracle Corporation") +// .prop("Max Memory", "948MB") +// .prop("Free Memory", "38MB") +// .endObject() +// +// .name("Web JVM Properties").beginObject() +// .prop("catalina.home", "/sonarsource/var/tmp/sonarsource/sssonarqube/tc") +// .prop("glowroot.tmp.dir", "/var/tmp/sonarsource/ssglowroot-agent") +// .prop("glowroot.adad.dir", "/var/tmp/sonarsource/ssglowroot-agent") +// .prop("java.specification.version", "1.8") +// .endObject() +// +// .name("Web Database Connectivity").beginObject() +// .prop("Driver", "PostgreSQL JDBC Driver") +// .prop("Driver Version", "PostgreSQL JDBC Driver") +// .prop("Pool Idle Connections", 2) +// .prop("Pool Max Connections", 50) +// .prop("URL", "jdbc:postgresql://next-rds.cn6pfc2xc6oq.us-east-1.rds.amazonaws.com/dory") +// .endObject(); +// +// json +// .name("Compute Engine JVM").beginObject() +// .prop("JVM Name", "Java HotSpot(TM) 64-Bit Server VM") +// .prop("JVM Vendor", "Oracle Corporation") +// .prop("Max Memory", "25MB") +// .prop("Free Memory", "8MB") +// .endObject(); +// +// json +// .name("Compute Engine JVM Properties").beginObject() +// .prop("java.ext.dirs", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") +// .prop("java.io.tmpdir", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") +// .prop("java.library.path", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") +// .prop("java.net.preferIPv4Stack", true) +// .prop("java.rmi.server.randomIDs", true) +// .prop("java.specification.version", "1.8") +// .endObject(); +// +// json.endObject().endArray(); +// +// json.name("Search Nodes"); +// json +// .beginArray() +// .beginObject() +// .prop("Name", "Parmelan") +// .prop("Host", "10.158.92.19") +// .prop("Health", "GREEN") +// .name("Health Causes").beginArray().endArray() +// .prop("Start Time", "2017-05-30T10:23:45") +// .prop("Processors", 2) +// .prop("Disk Available", "25GB") +// .prop("JVM Threads", 52) +// +// .name("JVM Properties").beginObject() +// .prop("java.ext.dirs", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") +// .prop("java.io.tmpdir", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") +// .prop("java.library.path", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") +// .prop("java.net.preferIPv4Stack", true) +// .prop("java.rmi.server.randomIDs", true) +// .endObject() +// +// .name("JVM").beginObject() +// .prop("java.ext.dirs", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") +// .prop("java.io.tmpdir", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") +// .prop("java.library.path", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") +// .prop("java.net.preferIPv4Stack", true) +// .prop("java.rmi.server.randomIDs", true) +// .endObject() +// +// .endObject() +// .endArray(); +// +// json.endObject(); +// } + } - json.endObject().endArray(); + private void writeGlobal(JsonWriter json) { + globalInfoLoader.load().forEach(section -> sectionToJson(section, json)); + } - json.name("Search Nodes"); - json - .beginArray() - .beginObject() - .prop("Name", "Parmelan") - .prop("Host", "10.158.92.19") - .prop("Health", "GREEN") - .name("Health Causes").beginArray().endArray() - .prop("Start Time", "2017-05-30T10:23:45") - .prop("Processors", 2) - .prop("Disk Available", "25GB") - .prop("JVM Threads", 52) + private void writeApplicationNodes(JsonWriter json) { + json.name("Application Nodes").beginArray(); - .name("JVM Properties").beginObject() - .prop("java.ext.dirs", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") - .prop("java.io.tmpdir", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") - .prop("java.library.path", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") - .prop("java.net.preferIPv4Stack", true) - .prop("java.rmi.server.randomIDs", true) - .endObject() + Collection appNodes = appNodesInfoLoader.load(); + for (NodeInfo applicationNode : appNodes) { + writeApplicationNode(json, applicationNode); + } + json.endArray(); + } - .name("JVM").beginObject() - .prop("java.ext.dirs", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") - .prop("java.io.tmpdir", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") - .prop("java.library.path", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext") - .prop("java.net.preferIPv4Stack", true) - .prop("java.rmi.server.randomIDs", true) - .endObject() + private void writeApplicationNode(JsonWriter json, NodeInfo applicationNode) { + json.beginObject(); + json.prop("Name", applicationNode.getName()); + applicationNode.getSections().forEach(section -> sectionToJson(section, json)); + json.endObject(); + } - .endObject() - .endArray(); + private static void sectionToJson(ProtobufSystemInfo.Section section, JsonWriter json) { + json.name(section.getName()); + json.beginObject(); + for (ProtobufSystemInfo.Attribute attribute : section.getAttributesList()) { + attributeToJson(json, attribute); + } + json.endObject(); + } - json.endObject(); + private static void attributeToJson(JsonWriter json, ProtobufSystemInfo.Attribute attribute) { + switch (attribute.getValueCase()) { + case BOOLEAN_VALUE: + json.prop(attribute.getKey(), attribute.getBooleanValue()); + break; + case LONG_VALUE: + json.prop(attribute.getKey(), attribute.getLongValue()); + break; + case DOUBLE_VALUE: + json.prop(attribute.getKey(), attribute.getDoubleValue()); + break; + case STRING_VALUE: + json.prop(attribute.getKey(), attribute.getStringValue()); + break; + case VALUE_NOT_SET: + json.name(attribute.getKey()).beginArray().values(attribute.getStringValuesList()).endArray(); + break; + default: + throw new IllegalArgumentException("Unsupported type: " + attribute.getValueCase()); } } } 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 39491bc60d9..e19cea3974f 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 @@ -19,18 +19,20 @@ */ package org.sonar.server.platform.ws; -import java.util.Arrays; -import java.util.Optional; +import java.util.List; import org.sonar.api.server.ws.Request; import org.sonar.api.server.ws.Response; import org.sonar.api.server.ws.WebService; import org.sonar.api.utils.text.JsonWriter; import org.sonar.ce.http.CeHttpClient; +import org.sonar.core.util.stream.MoreCollectors; import org.sonar.process.systeminfo.SystemInfoSection; +import org.sonar.process.systeminfo.SystemInfoUtils; import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo; import org.sonar.server.telemetry.TelemetryDataLoader; import org.sonar.server.user.UserSession; +import static java.util.Arrays.stream; import static org.sonar.server.telemetry.TelemetryDataJsonWriter.writeTelemetryData; /** @@ -38,6 +40,9 @@ import static org.sonar.server.telemetry.TelemetryDataJsonWriter.writeTelemetryD */ public class InfoAction implements SystemWsAction { + private static final String[] ORDERED_SECTION_NAMES = { + "System", "Database", "Web JVM Properties", "Web JVM State", "Search State", "Search Statistics", + "Compute Engine Database Connection", "Compute Engine JVM State", "Compute Engine Tasks"}; private final UserSession userSession; private final CeHttpClient ceHttpClient; private final SystemInfoSection[] systemInfoSections; @@ -73,14 +78,18 @@ public class InfoAction implements SystemWsAction { private void writeJson(JsonWriter json) { json.beginObject(); - Arrays.stream(systemInfoSections) + + List sections = stream(systemInfoSections) .map(SystemInfoSection::toProtobuf) + .collect(MoreCollectors.toArrayList()); + ceHttpClient.retrieveSystemInfo() + .ifPresent(ce -> sections.addAll(ce.getSectionsList())); + SystemInfoUtils + .order(sections, ORDERED_SECTION_NAMES) .forEach(section -> sectionToJson(section, json)); - Optional ceSysInfo = ceHttpClient.retrieveSystemInfo(); - if (ceSysInfo.isPresent()) { - ceSysInfo.get().getSectionsList().forEach(section -> sectionToJson(section, json)); - } + writeStatistics(json); + json.endObject(); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/OfficialDistributionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/OfficialDistributionTest.java new file mode 100644 index 00000000000..3f6a1cdb80a --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/OfficialDistributionTest.java @@ -0,0 +1,59 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.apache.commons.io.FileUtils; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.platform.Server; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + + +public class OfficialDistributionTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + private Server server = mock(Server.class); + private OfficialDistribution underTest = new OfficialDistribution(server); + + @Test + public void official_distribution() throws Exception { + File rootDir = temp.newFolder(); + FileUtils.write(new File(rootDir, OfficialDistribution.BRANDING_FILE_PATH), "1.2"); + when(server.getRootDir()).thenReturn(rootDir); + + assertThat(underTest.check()).isTrue(); + } + + @Test + public void not_an_official_distribution() throws Exception { + File rootDir = temp.newFolder(); + // branding file is missing + when(server.getRootDir()).thenReturn(rootDir); + + assertThat(underTest.check()).isFalse(); + } +} diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SystemSectionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/StandaloneSystemSectionTest.java similarity index 91% rename from server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SystemSectionTest.java rename to server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/StandaloneSystemSectionTest.java index c1ae9b3305d..ea5f52d1054 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/SystemSectionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/StandaloneSystemSectionTest.java @@ -19,13 +19,10 @@ */ package org.sonar.server.platform.monitoring; -import java.io.File; import java.util.Optional; -import org.apache.commons.io.FileUtils; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.rules.TemporaryFolder; import org.sonar.api.config.internal.MapSettings; import org.sonar.api.platform.Server; import org.sonar.api.security.SecurityRealm; @@ -47,14 +44,11 @@ import static org.mockito.Mockito.when; import static org.sonar.process.systeminfo.SystemInfoUtils.attribute; import static org.sonar.server.platform.monitoring.SystemInfoTesting.assertThatAttributeIs; -public class SystemSectionTest { +public class StandaloneSystemSectionTest { private static final String SERVER_ID_PROPERTY = "Server ID"; private static final String SERVER_ID_VALIDATED_PROPERTY = "Server ID validated"; - @Rule - public TemporaryFolder temp = new TemporaryFolder(); - @Rule public IdentityProviderRepositoryRule identityProviderRepository = new IdentityProviderRepositoryRule(); @@ -64,9 +58,10 @@ public class SystemSectionTest { private ServerLogging serverLogging = mock(ServerLogging.class); private SecurityRealmFactory securityRealmFactory = mock(SecurityRealmFactory.class); private TestStandaloneHealthChecker healthChecker = new TestStandaloneHealthChecker(); + private OfficialDistribution officialDistribution = mock(OfficialDistribution.class); - private SystemSection underTest = new SystemSection(settings.asConfig(), securityRealmFactory, identityProviderRepository, server, - serverLogging, serverIdLoader, healthChecker); + private StandaloneSystemSection underTest = new StandaloneSystemSection(settings.asConfig(), securityRealmFactory, identityProviderRepository, server, + serverLogging, serverIdLoader, officialDistribution, healthChecker); @Before public void setUp() throws Exception { @@ -118,10 +113,7 @@ public class SystemSectionTest { @Test public void official_distribution() throws Exception { - File rootDir = temp.newFolder(); - FileUtils.write(new File(rootDir, SystemSection.BRANDING_FILE_PATH), "1.2"); - - when(server.getRootDir()).thenReturn(rootDir); + when(officialDistribution.check()).thenReturn(true); ProtobufSystemInfo.Section protobuf = underTest.toProtobuf(); assertThatAttributeIs(protobuf, "Official Distribution", true); @@ -129,9 +121,7 @@ public class SystemSectionTest { @Test public void not_an_official_distribution() throws Exception { - File rootDir = temp.newFolder(); - // branding file is missing - when(server.getRootDir()).thenReturn(rootDir); + when(officialDistribution.check()).thenReturn(false); ProtobufSystemInfo.Section protobuf = underTest.toProtobuf(); assertThatAttributeIs(protobuf, "Official Distribution", false); @@ -214,4 +204,10 @@ public class SystemSectionTest { assertThatAttributeIs(protobuf, "Health", "YELLOW"); SystemInfoTesting.assertThatAttributeHasOnlyValues(protobuf, "Health Causes", asList("foo", "bar")); } + + @Test + public void return_nb_of_processors() { + ProtobufSystemInfo.Section protobuf = underTest.toProtobuf(); + assertThat(attribute(protobuf, "Processors").getLongValue()).isGreaterThan(0); + } } diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/NodeInfoTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/NodeInfoTest.java new file mode 100644 index 00000000000..04e67d6af3e --- /dev/null +++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/cluster/NodeInfoTest.java @@ -0,0 +1,42 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 SonarSource SA + * mailto:info 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.cluster; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class NodeInfoTest { + + @Test + public void test_equals_and_hashCode() { + NodeInfo foo = new NodeInfo("foo"); + NodeInfo bar = new NodeInfo("bar"); + NodeInfo bar2 = new NodeInfo("bar"); + + assertThat(foo.equals(foo)).isTrue(); + assertThat(foo.equals(bar)).isFalse(); + assertThat(bar.equals(bar2)).isTrue(); + + assertThat(bar.hashCode()).isEqualTo(bar.hashCode()); + assertThat(bar.hashCode()).isEqualTo(bar2.hashCode()); + } + +} -- 2.39.5