aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/sonar-ce/src/main/java/org/sonar/ce/CeQueueModule.java6
-rw-r--r--server/sonar-ce/src/main/java/org/sonar/ce/container/ComputeEngineContainerImpl.java14
-rw-r--r--server/sonar-ce/src/test/java/org/sonar/ce/container/ComputeEngineContainerImplTest.java2
-rw-r--r--server/sonar-main/pom.xml2
-rw-r--r--server/sonar-process/pom.xml1
-rw-r--r--server/sonar-process/src/test/java/org/sonar/process/cluster/hz/DistributedAnswerTest.java55
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/cluster/StartableHazelcastMember.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/health/ClusterHealth.java7
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStateSection.java46
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/StandaloneSystemSection.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/WebSystemInfoModule.java8
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/AppNodesInfoLoaderImpl.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/GlobalSystemSection.java10
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/LoggingSection.java55
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/NodeInfo.java39
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/NodeSystemSection.java16
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/SearchNodesInfoLoader.java (renamed from server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeSystemInfoModule.java)25
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/SearchNodesInfoLoaderImpl.java66
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/ws/BaseInfoWsAction.java101
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/ws/ClusterInfoAction.java238
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/ws/InfoAction.java78
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/ws/StandaloneInfoAction.java168
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/cluster/StartableHazelcastMemberTest.java106
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/health/ClusterHealthTest.java26
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/StandaloneSystemSectionTest.java19
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/platform/ws/InfoActionTest.java6
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/platform/ws/SystemWsTest.java7
-rw-r--r--server/sonar-web/src/main/js/api/system.ts23
-rw-r--r--server/sonar-web/src/main/js/apps/system/__tests__/utils-test.ts21
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/App.tsx14
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/ChangeLogLevelForm.tsx5
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/ClusterSysInfos.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/StandaloneSysInfos.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/__tests__/ClusterSysInfos-test.tsx53
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/__tests__/StandaloneSysInfos-test.tsx16
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ChangeLogLevelForm-test.tsx.snap4
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ClusterSysInfos-test.tsx.snap23
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/StandaloneSysInfos-test.tsx.snap18
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/info-items/HealthCard.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/info-items/HealthCauseItem.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/info-items/HealthItem.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCard-test.tsx2
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCauseItem-test.tsx6
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthItem-test.tsx13
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/__snapshots__/HealthCard-test.tsx.snap12
-rw-r--r--server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/__snapshots__/HealthItem-test.tsx.snap18
-rw-r--r--server/sonar-web/src/main/js/apps/system/utils.ts140
-rw-r--r--server/sonar-web/src/main/js/components/common/StatusIndicator.css2
49 files changed, 793 insertions, 729 deletions
diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/CeQueueModule.java b/server/sonar-ce/src/main/java/org/sonar/ce/CeQueueModule.java
index d8f37cd5e11..2811aa16c44 100644
--- a/server/sonar-ce/src/main/java/org/sonar/ce/CeQueueModule.java
+++ b/server/sonar-ce/src/main/java/org/sonar/ce/CeQueueModule.java
@@ -24,6 +24,8 @@ import org.sonar.ce.monitoring.CeTasksMBeanImpl;
import org.sonar.ce.queue.CeQueueInitializer;
import org.sonar.ce.queue.InternalCeQueueImpl;
import org.sonar.core.platform.Module;
+import org.sonar.process.systeminfo.JvmPropertiesSection;
+import org.sonar.process.systeminfo.JvmStateSection;
public class CeQueueModule extends Module {
@Override
@@ -35,7 +37,9 @@ public class CeQueueModule extends Module {
// queue monitoring
CEQueueStatusImpl.class,
CeTasksMBeanImpl.class,
-
+ new JvmStateSection("Compute Engine JVM State"),
+ new JvmPropertiesSection("Compute Engine JVM Properties"),
+
// init queue state and queue processing
CeQueueInitializer.class);
}
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 79f042caf3d..b62dca5b430 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,7 +49,6 @@ 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;
@@ -127,6 +126,9 @@ import org.sonar.server.platform.UrlSettings;
import org.sonar.server.platform.WebServerImpl;
import org.sonar.server.platform.db.migration.MigrationConfigurationModule;
import org.sonar.server.platform.db.migration.version.DatabaseVersion;
+import org.sonar.server.platform.monitoring.DatabaseSection;
+import org.sonar.server.platform.monitoring.cluster.ProcessInfoProvider;
+import org.sonar.server.platform.monitoring.cluster.LoggingSection;
import org.sonar.server.plugins.InstalledPluginReferentialFactory;
import org.sonar.server.plugins.ServerExtensionInstaller;
import org.sonar.server.plugins.privileged.PrivilegedPluginsBootstraper;
@@ -423,8 +425,14 @@ public class ComputeEngineContainerImpl implements ComputeEngineContainer {
if (props.valueAsBoolean(ProcessProperties.CLUSTER_ENABLED)) {
container.add(
StartableHazelcastMember.class,
- CeDistributedInformationImpl.class);
- container.add(CeSystemInfoModule.forClusterMode());
+
+ // system health
+ CeDistributedInformationImpl.class,
+
+ // system info
+ DatabaseSection.class,
+ ProcessInfoProvider.class,
+ LoggingSection.class);
} else {
container.add(StandaloneCeDistributedInformation.class);
}
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 640b8e76c43..4cf1cac4434 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
@@ -131,7 +131,7 @@ public class ComputeEngineContainerImplTest {
CONTAINER_ITSELF
+ 73 // level 4
+ 4 // content of CeConfigurationModule
- + 4 // content of CeQueueModule
+ + 6 // content of CeQueueModule
+ 4 // content of CeHttpModule
+ 3 // content of CeTaskCommonsModule
+ 4 // content of ProjectAnalysisTaskModule
diff --git a/server/sonar-main/pom.xml b/server/sonar-main/pom.xml
index 27e46c81cfb..eba72bb7f62 100644
--- a/server/sonar-main/pom.xml
+++ b/server/sonar-main/pom.xml
@@ -12,6 +12,8 @@
<artifactId>sonar-main</artifactId>
<name>SonarQube :: Main Process</name>
+ <description>Server process used to bootstrap Elasticsearch, Web Server and
+ Compute Engine processes. Could be merged with sonar-application.</description>
<properties>
<!--
diff --git a/server/sonar-process/pom.xml b/server/sonar-process/pom.xml
index 58adf12de38..00811e45e56 100644
--- a/server/sonar-process/pom.xml
+++ b/server/sonar-process/pom.xml
@@ -10,6 +10,7 @@
<artifactId>sonar-process</artifactId>
<name>SonarQube :: Process</name>
+ <description>Library shared by all kinds of server processes: main, web and compute engine</description>
<properties>
<sonar.exclusions>target/generated-sources/**/*</sonar.exclusions>
diff --git a/server/sonar-process/src/test/java/org/sonar/process/cluster/hz/DistributedAnswerTest.java b/server/sonar-process/src/test/java/org/sonar/process/cluster/hz/DistributedAnswerTest.java
index 6c9d8270a19..2cdf3d5dd75 100644
--- a/server/sonar-process/src/test/java/org/sonar/process/cluster/hz/DistributedAnswerTest.java
+++ b/server/sonar-process/src/test/java/org/sonar/process/cluster/hz/DistributedAnswerTest.java
@@ -21,7 +21,9 @@ package org.sonar.process.cluster.hz;
import com.hazelcast.core.Member;
import java.io.IOException;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@@ -30,10 +32,22 @@ import static org.mockito.Mockito.when;
public class DistributedAnswerTest {
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
private Member member = newMember("member1");
private DistributedAnswer underTest = new DistributedAnswer();
@Test
+ public void getMembers_return_all_members() {
+ underTest.setAnswer(member, "foo");
+ underTest.setTimedOut(newMember("bar"));
+ underTest.setFailed(newMember("baz"), new IOException("BOOM"));
+
+ assertThat(underTest.getMembers()).hasSize(3);
+ }
+
+ @Test
public void test_call_with_unknown_member() {
assertThat(underTest.getAnswer(member)).isEmpty();
assertThat(underTest.hasTimedOut(member)).isFalse();
@@ -46,6 +60,7 @@ public class DistributedAnswerTest {
assertThat(underTest.getAnswer(member)).hasValue("foo");
assertThat(underTest.hasTimedOut(member)).isFalse();
+ assertThat(underTest.getFailed(member)).isEmpty();
}
@Test
@@ -54,6 +69,7 @@ public class DistributedAnswerTest {
assertThat(underTest.getAnswer(member)).isEmpty();
assertThat(underTest.hasTimedOut(member)).isTrue();
+ assertThat(underTest.getFailed(member)).isEmpty();
}
@Test
@@ -61,6 +77,8 @@ public class DistributedAnswerTest {
IOException e = new IOException();
underTest.setFailed(member, e);
+ assertThat(underTest.getAnswer(member)).isEmpty();
+ assertThat(underTest.hasTimedOut(member)).isFalse();
assertThat(underTest.getFailed(member)).hasValue(e);
}
@@ -76,9 +94,46 @@ public class DistributedAnswerTest {
assertThat(underTest.getFailed(member)).hasValue(exception);
}
+ @Test
+ public void propagateExceptions_does_nothing_if_no_members() {
+ // no errors
+ underTest.propagateExceptions();
+ }
+
+ @Test
+ public void propagateExceptions_does_nothing_if_no_errors() {
+ underTest.setAnswer(newMember("foo"), "bar");
+
+ // no errors
+ underTest.propagateExceptions();
+ }
+
+ @Test
+ public void propagateExceptions_throws_ISE_if_at_least_one_timeout() {
+ underTest.setAnswer(newMember("bar"), "baz");
+ underTest.setTimedOut(newMember("foo"));
+
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Distributed cluster action timed out in cluster nodes foo");
+
+ underTest.propagateExceptions();
+ }
+
+ @Test
+ public void propagateExceptions_throws_ISE_if_at_least_one_failure() {
+ underTest.setAnswer(newMember("bar"), "baz");
+ underTest.setFailed(newMember("foo"), new IOException("BOOM"));
+
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Distributed cluster action in cluster nodes foo (other nodes may have timed out)");
+
+ underTest.propagateExceptions();
+ }
+
private static Member newMember(String uuid) {
Member member = mock(Member.class);
when(member.getUuid()).thenReturn(uuid);
+ when(member.getStringAttribute(HazelcastMember.Attribute.NODE_NAME)).thenReturn(uuid);
return member;
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/cluster/StartableHazelcastMember.java b/server/sonar-server/src/main/java/org/sonar/server/cluster/StartableHazelcastMember.java
index e746c21435d..1e430e17d29 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/cluster/StartableHazelcastMember.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/cluster/StartableHazelcastMember.java
@@ -22,7 +22,6 @@ package org.sonar.server.cluster;
import com.hazelcast.core.Cluster;
import com.hazelcast.core.IAtomicReference;
import com.hazelcast.core.MemberSelector;
-import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;
@@ -55,12 +54,12 @@ import static org.sonar.process.ProcessProperties.CLUSTER_NODE_TYPE;
public class StartableHazelcastMember implements HazelcastMember, Startable {
private final Configuration config;
- private final NetworkUtils networkUtils;
+ private final NetworkUtils network;
private HazelcastMember member = null;
- public StartableHazelcastMember(Configuration config, NetworkUtils networkUtils) {
+ public StartableHazelcastMember(Configuration config, NetworkUtils network) {
this.config = config;
- this.networkUtils = networkUtils;
+ this.network = network;
}
@Override
@@ -136,7 +135,7 @@ public class StartableHazelcastMember implements HazelcastMember, Startable {
String networkAddress = config.get(CLUSTER_NODE_HOST).orElseThrow(() -> new IllegalStateException("Missing node host"));
int freePort;
try {
- freePort = networkUtils.getNextAvailablePort(InetAddress.getByName(networkAddress));
+ freePort = network.getNextAvailablePort(network.toInetAddress(networkAddress));
} catch (UnknownHostException e) {
throw new IllegalStateException(format("Can not resolve address %s", networkAddress), e);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/health/ClusterHealth.java b/server/sonar-server/src/main/java/org/sonar/server/health/ClusterHealth.java
index 26a54ce0bcf..53d75a4dede 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/health/ClusterHealth.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/health/ClusterHealth.java
@@ -20,6 +20,7 @@
package org.sonar.server.health;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
import org.sonar.process.cluster.health.NodeHealth;
@@ -43,6 +44,12 @@ public class ClusterHealth {
return nodes;
}
+ public Optional<NodeHealth> getNodeHealth(String nodeName) {
+ return nodes.stream()
+ .filter(node -> nodeName.equals(node.getDetails().getName()))
+ .findFirst();
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStateSection.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStateSection.java
index 900cb59ca14..40d8803dbf9 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStateSection.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/EsStateSection.java
@@ -60,29 +60,39 @@ public class EsStateSection implements SystemInfoSection {
}
private void completeNodeAttributes(ProtobufSystemInfo.Section.Builder protobuf) {
- NodesStatsResponse nodesStats = esClient.prepareNodesStats().all().get();
+ NodesStatsResponse nodesStats = esClient.prepareNodesStats()
+ .setFs(true)
+ .setProcess(true)
+ .setJvm(true)
+ .setIndices(true)
+ .setBreaker(true)
+ .get();
if (!nodesStats.getNodes().isEmpty()) {
NodeStats stats = nodesStats.getNodes().get(0);
- setAttribute(protobuf, "Disk Available", byteCountToDisplaySize(stats.getFs().getTotal().getAvailable().getBytes()));
- setAttribute(protobuf, "Store Size", byteCountToDisplaySize(stats.getIndices().getStore().getSizeInBytes()));
- setAttribute(protobuf, "Open File Descriptors", stats.getProcess().getOpenFileDescriptors());
- setAttribute(protobuf, "Max File Descriptors", stats.getProcess().getMaxFileDescriptors());
- setAttribute(protobuf, "Spinning", stats.getFs().getTotal().getSpins());
- setAttribute(protobuf, "JVM Heap Usage", formatPercent(stats.getJvm().getMem().getHeapUsedPercent()));
- setAttribute(protobuf, "JVM Heap Used", byteCountToDisplaySize(stats.getJvm().getMem().getHeapUsed().getBytes()));
- setAttribute(protobuf, "JVM Heap Max", byteCountToDisplaySize(stats.getJvm().getMem().getHeapMax().getBytes()));
- setAttribute(protobuf, "JVM Non Heap Used", byteCountToDisplaySize(stats.getJvm().getMem().getNonHeapUsed().getBytes()));
- setAttribute(protobuf, "JVM Threads", stats.getJvm().getThreads().getCount());
- setAttribute(protobuf, "Field Data Memory", byteCountToDisplaySize(stats.getIndices().getFieldData().getMemorySizeInBytes()));
- setAttribute(protobuf, "Field Data Circuit Breaker Limit", byteCountToDisplaySize(stats.getBreaker().getStats(CircuitBreaker.FIELDDATA).getLimit()));
- setAttribute(protobuf, "Field Data Circuit Breaker Estimation", byteCountToDisplaySize(stats.getBreaker().getStats(CircuitBreaker.FIELDDATA).getEstimated()));
- setAttribute(protobuf, "Request Circuit Breaker Limit", byteCountToDisplaySize(stats.getBreaker().getStats(CircuitBreaker.REQUEST).getLimit()));
- setAttribute(protobuf, "Request Circuit Breaker Estimation", byteCountToDisplaySize(stats.getBreaker().getStats(CircuitBreaker.REQUEST).getEstimated()));
- setAttribute(protobuf, "Query Cache Memory", byteCountToDisplaySize(stats.getIndices().getQueryCache().getMemorySizeInBytes()));
- setAttribute(protobuf, "Request Cache Memory", byteCountToDisplaySize(stats.getIndices().getRequestCache().getMemorySizeInBytes()));
+ toProtobuf(stats, protobuf);
}
}
+ public static void toProtobuf(NodeStats stats, ProtobufSystemInfo.Section.Builder protobuf) {
+ setAttribute(protobuf, "Disk Available", byteCountToDisplaySize(stats.getFs().getTotal().getAvailable().getBytes()));
+ setAttribute(protobuf, "Store Size", byteCountToDisplaySize(stats.getIndices().getStore().getSizeInBytes()));
+ setAttribute(protobuf, "Open File Descriptors", stats.getProcess().getOpenFileDescriptors());
+ setAttribute(protobuf, "Max File Descriptors", stats.getProcess().getMaxFileDescriptors());
+ setAttribute(protobuf, "Spinning", stats.getFs().getTotal().getSpins());
+ setAttribute(protobuf, "JVM Heap Usage", formatPercent(stats.getJvm().getMem().getHeapUsedPercent()));
+ setAttribute(protobuf, "JVM Heap Used", byteCountToDisplaySize(stats.getJvm().getMem().getHeapUsed().getBytes()));
+ setAttribute(protobuf, "JVM Heap Max", byteCountToDisplaySize(stats.getJvm().getMem().getHeapMax().getBytes()));
+ setAttribute(protobuf, "JVM Non Heap Used", byteCountToDisplaySize(stats.getJvm().getMem().getNonHeapUsed().getBytes()));
+ setAttribute(protobuf, "JVM Threads", stats.getJvm().getThreads().getCount());
+ setAttribute(protobuf, "Field Data Memory", byteCountToDisplaySize(stats.getIndices().getFieldData().getMemorySizeInBytes()));
+ setAttribute(protobuf, "Field Data Circuit Breaker Limit", byteCountToDisplaySize(stats.getBreaker().getStats(CircuitBreaker.FIELDDATA).getLimit()));
+ setAttribute(protobuf, "Field Data Circuit Breaker Estimation", byteCountToDisplaySize(stats.getBreaker().getStats(CircuitBreaker.FIELDDATA).getEstimated()));
+ setAttribute(protobuf, "Request Circuit Breaker Limit", byteCountToDisplaySize(stats.getBreaker().getStats(CircuitBreaker.REQUEST).getLimit()));
+ setAttribute(protobuf, "Request Circuit Breaker Estimation", byteCountToDisplaySize(stats.getBreaker().getStats(CircuitBreaker.REQUEST).getEstimated()));
+ setAttribute(protobuf, "Query Cache Memory", byteCountToDisplaySize(stats.getIndices().getQueryCache().getMemorySizeInBytes()));
+ setAttribute(protobuf, "Request Cache Memory", byteCountToDisplaySize(stats.getIndices().getRequestCache().getMemorySizeInBytes()));
+ }
+
private ClusterStatsResponse clusterStats() {
return esClient.prepareClusterStats().get();
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/StandaloneSystemSection.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/StandaloneSystemSection.java
index acdffa2efb5..799fcbb4023 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/StandaloneSystemSection.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/StandaloneSystemSection.java
@@ -32,8 +32,6 @@ import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.process.ProcessProperties;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import org.sonar.server.authentication.IdentityProviderRepository;
-import org.sonar.server.health.Health;
-import org.sonar.server.health.HealthChecker;
import org.sonar.server.platform.ServerIdLoader;
import org.sonar.server.platform.ServerLogging;
import org.sonar.server.user.SecurityRealmFactory;
@@ -51,11 +49,10 @@ public class StandaloneSystemSection extends BaseSectionMBean implements SystemS
private final ServerLogging serverLogging;
private final ServerIdLoader serverIdLoader;
private final OfficialDistribution officialDistribution;
- private final HealthChecker healthChecker;
public StandaloneSystemSection(Configuration config, SecurityRealmFactory securityRealmFactory,
IdentityProviderRepository identityProviderRepository, Server server, ServerLogging serverLogging,
- ServerIdLoader serverIdLoader, OfficialDistribution officialDistribution, HealthChecker healthChecker) {
+ ServerIdLoader serverIdLoader, OfficialDistribution officialDistribution) {
this.config = config;
this.securityRealmFactory = securityRealmFactory;
this.identityProviderRepository = identityProviderRepository;
@@ -63,7 +60,6 @@ public class StandaloneSystemSection extends BaseSectionMBean implements SystemS
this.serverLogging = serverLogging;
this.serverIdLoader = serverIdLoader;
this.officialDistribution = officialDistribution;
- this.healthChecker = healthChecker;
}
@Override
@@ -123,9 +119,6 @@ public class StandaloneSystemSection extends BaseSectionMBean implements SystemS
setAttribute(protobuf, "Server ID", serverId.getId());
setAttribute(protobuf, "Server ID validated", serverId.isValid());
});
- Health health = healthChecker.checkNode();
- setAttribute(protobuf, "Health", health.getStatus().name());
- setAttribute(protobuf, "Health Causes", health.getCauses());
setAttribute(protobuf, "Version", getVersion());
setAttribute(protobuf, "External User Authentication", getExternalUserAuthentication());
addIfNotEmpty(protobuf, "Accepted external identity providers", getEnabledIdentityProviders());
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 b5f495f2c64..01dec926e3a 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
@@ -25,9 +25,11 @@ 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.LoggingSection;
import org.sonar.server.platform.monitoring.cluster.NodeSystemSection;
+import org.sonar.server.platform.monitoring.cluster.SearchNodesInfoLoaderImpl;
import org.sonar.server.platform.ws.ClusterInfoAction;
-import org.sonar.server.platform.ws.StandaloneInfoAction;
+import org.sonar.server.platform.ws.InfoAction;
public class WebSystemInfoModule {
@@ -48,7 +50,7 @@ public class WebSystemInfoModule {
OfficialDistribution.class,
- StandaloneInfoAction.class
+ InfoAction.class
};
}
@@ -59,6 +61,7 @@ public class WebSystemInfoModule {
DatabaseSection.class,
EsStatisticsSection.class,
GlobalSystemSection.class,
+ LoggingSection.class,
NodeSystemSection.class,
PluginsSection.class,
SettingsSection.class,
@@ -68,6 +71,7 @@ public class WebSystemInfoModule {
ProcessInfoProvider.class,
GlobalInfoLoader.class,
AppNodesInfoLoaderImpl.class,
+ SearchNodesInfoLoaderImpl.class,
ClusterInfoAction.class
};
}
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
index 03eaaa09dfe..67c943028f0 100644
--- 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
@@ -50,9 +50,6 @@ public class AppNodesInfoLoaderImpl implements AppNodesInfoLoader {
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);
}
@@ -64,13 +61,13 @@ public class AppNodesInfoLoaderImpl implements AppNodesInfoLoader {
}
}
- private void completeNodeInfo(DistributedAnswer<ProtobufSystemInfo.SystemInfo> distributedAnswer, Member member, NodeInfo nodeInfo) {
+ private static void completeNodeInfo(DistributedAnswer<ProtobufSystemInfo.SystemInfo> distributedAnswer, Member member, NodeInfo nodeInfo) {
Optional<ProtobufSystemInfo.SystemInfo> nodeAnswer = distributedAnswer.getAnswer(member);
Optional<Exception> failure = distributedAnswer.getFailed(member);
if (distributedAnswer.hasTimedOut(member)) {
- nodeInfo.setAttribute("Error", "Failed to retrieve information on time");
+ nodeInfo.setErrorMessage("Failed to retrieve information on time");
} else if (failure.isPresent()) {
- nodeInfo.setAttribute("Error", "Failed to retrieve information: " + failure.get().getMessage());
+ nodeInfo.setErrorMessage("Failed to retrieve information: " + failure.get().getMessage());
} else if (nodeAnswer.isPresent()) {
nodeAnswer.get().getSectionsList().forEach(nodeInfo::addSection);
}
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
index 90875c5d7b6..e2999dcb56a 100644
--- 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
@@ -33,8 +33,6 @@ 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;
@@ -48,15 +46,13 @@ public class GlobalSystemSection implements SystemInfoSection, Global {
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) {
+ IdentityProviderRepository identityProviderRepository) {
this.config = config;
this.serverIdLoader = serverIdLoader;
this.securityRealmFactory = securityRealmFactory;
this.identityProviderRepository = identityProviderRepository;
- this.healthChecker = healthChecker;
}
@Override
@@ -64,10 +60,6 @@ public class GlobalSystemSection implements SystemInfoSection, Global {
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());
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/LoggingSection.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/LoggingSection.java
new file mode 100644
index 00000000000..1af901bb417
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/LoggingSection.java
@@ -0,0 +1,55 @@
+/*
+ * 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.SonarQubeSide;
+import org.sonar.api.SonarRuntime;
+import org.sonar.api.ce.ComputeEngineSide;
+import org.sonar.api.server.ServerSide;
+import org.sonar.process.systeminfo.SystemInfoSection;
+import org.sonar.process.systeminfo.SystemInfoUtils;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.server.platform.ServerLogging;
+
+@ComputeEngineSide
+@ServerSide
+public class LoggingSection implements SystemInfoSection {
+
+ private final SonarRuntime runtime;
+ private final ServerLogging logging;
+
+ public LoggingSection(SonarRuntime runtime, ServerLogging logging) {
+ this.runtime = runtime;
+ this.logging = logging;
+ }
+
+ @Override
+ public ProtobufSystemInfo.Section toProtobuf() {
+ ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder();
+ if (runtime.getSonarQubeSide() == SonarQubeSide.COMPUTE_ENGINE) {
+ protobuf.setName("Compute Engine Logging");
+ } else {
+ protobuf.setName("Web Logging");
+ }
+ SystemInfoUtils.setAttribute(protobuf, "Logs Level", logging.getRootLoggerLevel().name());
+ SystemInfoUtils.setAttribute(protobuf, "Logs Dir", logging.getLogsDir().getAbsolutePath());
+ return protobuf.build();
+ }
+}
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
index 3a53e1b829c..c9a368e4264 100644
--- 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
@@ -20,15 +20,23 @@
package org.sonar.server.platform.monitoring.cluster;
import java.util.ArrayList;
-import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
+import java.util.Optional;
+import javax.annotation.Nullable;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+/**
+ * Represents the system information of a cluster node. In the case of
+ * application node, it merges information from Web Server and Compute
+ * Engine processes.
+ *
+ */
public class NodeInfo {
private final String name;
- private final Map<String, String> attributes = new LinkedHashMap<>();
+ private String host = null;
+ private Long startedAt = null;
+ private String errorMessage = null;
private final List<ProtobufSystemInfo.Section> sections = new ArrayList<>();
public NodeInfo(String name) {
@@ -39,13 +47,28 @@ public class NodeInfo {
return name;
}
- public NodeInfo setAttribute(String key, String value) {
- this.attributes.put(key, value);
- return this;
+ public Optional<String> getHost() {
+ return Optional.ofNullable(host);
+ }
+
+ public void setHost(@Nullable String s) {
+ this.host = s;
+ }
+
+ public Optional<Long> getStartedAt() {
+ return Optional.ofNullable(startedAt);
+ }
+
+ public void setStartedAt(@Nullable Long l) {
+ this.startedAt = l;
+ }
+
+ public Optional<String> getErrorMessage() {
+ return Optional.ofNullable(errorMessage);
}
- public Map<String, String> getAttributes() {
- return attributes;
+ public void setErrorMessage(@Nullable String s) {
+ this.errorMessage = s;
}
public NodeInfo addSection(ProtobufSystemInfo.Section section) {
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
index 8ab8a07f1e2..e2def825669 100644
--- 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
@@ -25,9 +25,6 @@ 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;
@@ -37,17 +34,12 @@ 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) {
+ public NodeSystemSection(Configuration config, Server server, OfficialDistribution officialDistribution) {
this.config = config;
this.server = server;
- this.serverLogging = serverLogging;
this.officialDistribution = officialDistribution;
- this.healthChecker = healthChecker;
}
@Override
@@ -55,16 +47,12 @@ public class NodeSystemSection implements SystemInfoSection {
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());
+ setAttribute(protobuf, "Processors", Runtime.getRuntime().availableProcessors());
return protobuf.build();
}
diff --git a/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeSystemInfoModule.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/SearchNodesInfoLoader.java
index be53383ebee..3b91ffbf9ba 100644
--- a/server/sonar-ce/src/main/java/org/sonar/ce/monitoring/CeSystemInfoModule.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/SearchNodesInfoLoader.java
@@ -17,25 +17,14 @@
* 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;
+package org.sonar.server.platform.monitoring.cluster;
-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 {
+import java.util.Collection;
- 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
- };
- }
+/**
+ * Loads "system information" of all Elasticsearch nodes.
+ */
+public interface SearchNodesInfoLoader {
+ Collection<NodeInfo> load();
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/SearchNodesInfoLoaderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/SearchNodesInfoLoaderImpl.java
new file mode 100644
index 00000000000..08703a608b3
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/monitoring/cluster/SearchNodesInfoLoaderImpl.java
@@ -0,0 +1,66 @@
+/*
+ * 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.Collection;
+import java.util.List;
+import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
+import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
+import org.sonar.api.server.ServerSide;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.server.es.EsClient;
+import org.sonar.server.platform.monitoring.EsStateSection;
+
+@ServerSide
+public class SearchNodesInfoLoaderImpl implements SearchNodesInfoLoader {
+
+ private final EsClient esClient;
+
+ public SearchNodesInfoLoaderImpl(EsClient esClient) {
+ this.esClient = esClient;
+ }
+
+ public Collection<NodeInfo> load() {
+ NodesStatsResponse nodesStats = esClient.prepareNodesStats()
+ .setFs(true)
+ .setProcess(true)
+ .setJvm(true)
+ .setIndices(true)
+ .setBreaker(true)
+ .get();
+ List<NodeInfo> result = new ArrayList<>();
+ nodesStats.getNodes().forEach(nodeStat -> result.add(toNodeInfo(nodeStat)));
+ return result;
+ }
+
+ private static NodeInfo toNodeInfo(NodeStats stat) {
+ String nodeName = stat.getNode().getName();
+ NodeInfo info = new NodeInfo(nodeName);
+
+ ProtobufSystemInfo.Section.Builder section = ProtobufSystemInfo.Section.newBuilder();
+ section.setName("Search State");
+ EsStateSection.toProtobuf(stat, section);
+ info.addSection(section.build());
+
+ return info;
+ }
+
+}
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 b69534bc605..5d015b81036 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
@@ -114,7 +114,6 @@ import org.sonar.server.platform.web.requestid.HttpRequestIdModule;
import org.sonar.server.platform.ws.ChangeLogLevelAction;
import org.sonar.server.platform.ws.DbMigrationStatusAction;
import org.sonar.server.platform.ws.HealthActionModule;
-import org.sonar.server.platform.ws.InfoAction;
import org.sonar.server.platform.ws.L10nWs;
import org.sonar.server.platform.ws.LogsAction;
import org.sonar.server.platform.ws.MigrateDbAction;
@@ -542,7 +541,6 @@ public class PlatformLevel4 extends PlatformLevel {
addIfStartupLeader(TelemetryDaemon.class, TelemetryClient.class);
// system info
- add(InfoAction.class);
addIfCluster(WebSystemInfoModule.forClusterMode()).otherwiseAdd(WebSystemInfoModule.forStandaloneMode());
addAll(level4AddedComponents);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/BaseInfoWsAction.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/BaseInfoWsAction.java
new file mode 100644
index 00000000000..d6f821f2d17
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/BaseInfoWsAction.java
@@ -0,0 +1,101 @@
+/*
+ * 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.ws;
+
+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.SystemInfoUtils;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.server.user.UserSession;
+
+public abstract class BaseInfoWsAction implements SystemWsAction {
+
+ private static final String[] ORDERED_SECTION_NAMES = {
+ "System", "Database", "Plugins",
+ "Web JVM State", "Web Logging", "Web JVM Properties",
+ "Search State", "Search Statistics",
+ "Compute Engine Database Connection", "Compute Engine JVM State", "Compute Engine Logging", "Compute Engine Tasks", "Compute Engine JVM Properties"};
+
+ private final UserSession userSession;
+
+ public BaseInfoWsAction(UserSession userSession) {
+ this.userSession = userSession;
+ }
+
+ @Override
+ public void define(WebService.NewController controller) {
+ controller.createAction("info")
+ .setDescription("Get detailed information about system configuration.<br/>" +
+ "Requires 'Administer' permissions.<br/>" +
+ "Since 5.5, this web service becomes internal in order to more easily update result.")
+ .setSince("5.1")
+ .setInternal(true)
+ .setResponseExample(getClass().getResource("/org/sonar/server/platform/ws/info-example.json"))
+ .setHandler(this);
+ }
+
+ @Override
+ public void handle(Request request, Response response) {
+ userSession.checkIsSystemAdministrator();
+ doHandle(request, response);
+ }
+
+ protected abstract void doHandle(Request request, Response response);
+
+ protected void writeSectionsToJson(Collection<ProtobufSystemInfo.Section> sections, JsonWriter json) {
+ SystemInfoUtils
+ .order(sections, ORDERED_SECTION_NAMES)
+ .forEach(section -> writeSectionToJson(section, json));
+ }
+
+ protected void writeSectionToJson(ProtobufSystemInfo.Section section, JsonWriter json) {
+ json.name(section.getName());
+ json.beginObject();
+ for (ProtobufSystemInfo.Attribute attribute : section.getAttributesList()) {
+ writeAttributeToJson(attribute, json);
+ }
+ json.endObject();
+ }
+
+ protected void writeAttributeToJson(ProtobufSystemInfo.Attribute attribute, JsonWriter json) {
+ 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/ClusterInfoAction.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/ClusterInfoAction.java
index 87264373367..6f5e7d9bde4 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
@@ -22,236 +22,82 @@ package org.sonar.server.platform.ws;
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.health.ClusterHealth;
+import org.sonar.server.health.HealthChecker;
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.platform.monitoring.cluster.SearchNodesInfoLoader;
import org.sonar.server.user.UserSession;
-public class ClusterInfoAction implements SystemWsAction {
+public class ClusterInfoAction extends BaseInfoWsAction {
- private final UserSession userSession;
private final GlobalInfoLoader globalInfoLoader;
private final AppNodesInfoLoader appNodesInfoLoader;
+ private final SearchNodesInfoLoader searchNodesInfoLoader;
+ private final HealthChecker healthChecker;
- public ClusterInfoAction(UserSession userSession, GlobalInfoLoader globalInfoLoader, AppNodesInfoLoader appNodesInfoLoader) {
- this.userSession = userSession;
+ public ClusterInfoAction(UserSession userSession, GlobalInfoLoader globalInfoLoader,
+ AppNodesInfoLoader appNodesInfoLoader, SearchNodesInfoLoader searchNodesInfoLoader, HealthChecker healthChecker) {
+ super(userSession);
this.globalInfoLoader = globalInfoLoader;
this.appNodesInfoLoader = appNodesInfoLoader;
+ this.searchNodesInfoLoader = searchNodesInfoLoader;
+ this.healthChecker = healthChecker;
}
@Override
- public void define(WebService.NewController controller) {
- controller.createAction("cluster_info")
- .setDescription("WIP")
- .setSince("6.6")
- .setInternal(true)
- .setResponseExample(getClass().getResource("/org/sonar/server/platform/ws/info-example.json"))
- .setHandler(this);
- }
-
- @Override
- public void handle(Request request, Response response) {
- userSession.checkIsSystemAdministrator();
-
+ protected void doHandle(Request request, Response response) {
+ ClusterHealth clusterHealth = healthChecker.checkCluster();
try (JsonWriter json = response.newJsonWriter()) {
json.beginObject();
- writeGlobal(json);
- writeApplicationNodes(json);
+
+ json.prop("Health", clusterHealth.getHealth().getStatus().name());
+ json.name("Health Causes").beginArray().values(clusterHealth.getHealth().getCauses()).endArray();
+
+ writeGlobalSections(json);
+ writeApplicationNodes(json, clusterHealth);
+ writeSearchNodes(json, clusterHealth);
json.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();
-// }
}
- private void writeGlobal(JsonWriter json) {
- globalInfoLoader.load().forEach(section -> sectionToJson(section, json));
+ private void writeGlobalSections(JsonWriter json) {
+ globalInfoLoader.load().forEach(section -> writeSectionToJson(section, json));
}
- private void writeApplicationNodes(JsonWriter json) {
+ private void writeApplicationNodes(JsonWriter json, ClusterHealth clusterHealth) {
json.name("Application Nodes").beginArray();
Collection<NodeInfo> appNodes = appNodesInfoLoader.load();
for (NodeInfo applicationNode : appNodes) {
- writeApplicationNode(json, applicationNode);
+ writeNodeInfoToJson(applicationNode, clusterHealth, json);
}
json.endArray();
}
- private void writeApplicationNode(JsonWriter json, NodeInfo applicationNode) {
- json.beginObject();
- json.prop("Name", applicationNode.getName());
- applicationNode.getSections().forEach(section -> sectionToJson(section, json));
- json.endObject();
+ private void writeSearchNodes(JsonWriter json, ClusterHealth clusterHealth) {
+ json.name("Search Nodes").beginArray();
+
+ Collection<NodeInfo> searchNodes = searchNodesInfoLoader.load();
+ searchNodes.forEach(node -> writeNodeInfoToJson(node, clusterHealth, json));
+ json.endArray();
}
- private static void sectionToJson(ProtobufSystemInfo.Section section, JsonWriter json) {
- json.name(section.getName());
+ private void writeNodeInfoToJson(NodeInfo nodeInfo, ClusterHealth clusterHealth, JsonWriter json) {
json.beginObject();
- for (ProtobufSystemInfo.Attribute attribute : section.getAttributesList()) {
- attributeToJson(json, attribute);
- }
- json.endObject();
- }
+ json.prop("Name", nodeInfo.getName());
+ json.prop("Error", nodeInfo.getErrorMessage().orElse(null));
+ json.prop("Host", nodeInfo.getHost().orElse(null));
+ json.prop("Started At", nodeInfo.getStartedAt().orElse(null));
- 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());
- }
+ clusterHealth.getNodeHealth(nodeInfo.getName()).ifPresent(h -> {
+ json.prop("Health", h.getStatus().name());
+ json.name("Health Causes").beginArray().values(h.getCauses()).endArray();
+ });
+
+ writeSectionsToJson(nodeInfo.getSections(), json);
+ json.endObject();
}
}
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 e19cea3974f..0011675154c 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
@@ -22,13 +22,13 @@ package org.sonar.server.platform.ws;
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.health.Health;
+import org.sonar.server.health.HealthChecker;
import org.sonar.server.telemetry.TelemetryDataLoader;
import org.sonar.server.user.UserSession;
@@ -38,39 +38,24 @@ import static org.sonar.server.telemetry.TelemetryDataJsonWriter.writeTelemetryD
/**
* Implementation of the {@code info} action for the System WebService.
*/
-public class InfoAction implements SystemWsAction {
+public class InfoAction extends BaseInfoWsAction {
- 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;
+ private final HealthChecker healthChecker;
private final TelemetryDataLoader statistics;
- public InfoAction(UserSession userSession, CeHttpClient ceHttpClient, TelemetryDataLoader statistics, SystemInfoSection... systemInfoSections) {
- this.userSession = userSession;
+ public InfoAction(UserSession userSession, CeHttpClient ceHttpClient, HealthChecker healthChecker, TelemetryDataLoader statistics,
+ SystemInfoSection... systemInfoSections) {
+ super(userSession);
this.ceHttpClient = ceHttpClient;
+ this.healthChecker = healthChecker;
this.statistics = statistics;
this.systemInfoSections = systemInfoSections;
}
@Override
- public void define(WebService.NewController controller) {
- controller.createAction("info")
- .setDescription("Get detailed information about system configuration.<br/>" +
- "Requires 'Administer' permissions.<br/>" +
- "Since 5.5, this web service becomes internal in order to more easily update result.")
- .setSince("5.1")
- .setInternal(true)
- .setResponseExample(getClass().getResource("/org/sonar/server/platform/ws/info-example.json"))
- .setHandler(this);
- }
-
- @Override
- public void handle(Request request, Response response) {
- userSession.checkIsSystemAdministrator();
-
+ protected void doHandle(Request request, Response response) {
try (JsonWriter json = response.newJsonWriter()) {
writeJson(json);
}
@@ -79,53 +64,28 @@ public class InfoAction implements SystemWsAction {
private void writeJson(JsonWriter json) {
json.beginObject();
+ writeHealthToJson(json);
List<ProtobufSystemInfo.Section> 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));
- writeStatistics(json);
+ writeSectionsToJson(sections, json);
+ writeStatisticsToJson(json);
json.endObject();
}
- private void writeStatistics(JsonWriter json) {
- json.name("Statistics");
- writeTelemetryData(json, statistics.load());
+ private void writeHealthToJson(JsonWriter json) {
+ Health health = healthChecker.checkNode();
+ json.prop("Health", health.getStatus().name());
+ json.name("Health Causes").beginArray().values(health.getCauses()).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();
+ private void writeStatisticsToJson(JsonWriter json) {
+ json.name("Statistics");
+ writeTelemetryData(json, statistics.load());
}
- 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/StandaloneInfoAction.java b/server/sonar-server/src/main/java/org/sonar/server/platform/ws/StandaloneInfoAction.java
deleted file mode 100644
index adb92772f98..00000000000
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/ws/StandaloneInfoAction.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * 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.ws;
-
-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.server.user.UserSession;
-
-public class StandaloneInfoAction implements SystemWsAction {
-
- private final UserSession userSession;
-
- public StandaloneInfoAction(UserSession userSession) {
- this.userSession = userSession;
- }
-
- @Override
- public void define(WebService.NewController controller) {
- controller.createAction("standalone_info")
- .setDescription("WIP")
- .setSince("6.6")
- .setInternal(true)
- .setResponseExample(getClass().getResource("/org/sonar/server/platform/ws/info-example.json"))
- .setHandler(this);
- }
-
- @Override
- public void handle(Request request, Response response) {
- userSession.checkIsSystemAdministrator();
-
- try (JsonWriter json = response.newJsonWriter()) {
- json.beginObject();
-
- // global section
- json
- .prop("Server Id", "ABC123")
- .prop("Health", "RED")
- .prop("Host", "10.158.92.16")
- .prop("Start Time", "2017-05-30T10:23:45")
- .prop("Official Distribution", true)
- .prop("Processors", 4)
- .prop("Disk Available", "25GB")
- .prop("JVM Threads", 52);
- json
- .name("Health Causes")
- .beginArray().beginObject().prop("message", "Db connectivity error").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("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
- .name("Search 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();
-
- json.name("Search 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();
-
- json.endObject();
- }
- }
-}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/cluster/StartableHazelcastMemberTest.java b/server/sonar-server/src/test/java/org/sonar/server/cluster/StartableHazelcastMemberTest.java
new file mode 100644
index 00000000000..475079444ec
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/cluster/StartableHazelcastMemberTest.java
@@ -0,0 +1,106 @@
+/*
+ * 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.cluster;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.function.Supplier;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.process.NetworkUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+
+public class StartableHazelcastMemberTest {
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private MapSettings settings = new MapSettings();
+ private String loopback = InetAddress.getLoopbackAddress().getHostAddress();
+
+ @Test
+ public void start_initializes_hazelcast() {
+ completeValidSettings();
+ StartableHazelcastMember underTest = new StartableHazelcastMember(settings.asConfig(), NetworkUtils.INSTANCE);
+ verifyStopped(underTest);
+
+ underTest.start();
+
+ assertThat(underTest.getUuid()).isNotEmpty();
+ assertThat(underTest.getCluster().getMembers()).hasSize(1);
+ assertThat(underTest.getMemberUuids()).containsExactly(underTest.getUuid());
+ assertThat(underTest.getSet("foo")).isNotNull();
+ assertThat(underTest.getReplicatedMap("foo")).isNotNull();
+ assertThat(underTest.getAtomicReference("foo")).isNotNull();
+ assertThat(underTest.getList("foo")).isNotNull();
+ assertThat(underTest.getMap("foo")).isNotNull();
+ assertThat(underTest.getLock("foo")).isNotNull();
+ assertThat(underTest.getClusterTime()).isGreaterThan(0);
+
+ underTest.stop();
+
+ verifyStopped(underTest);
+ }
+
+ @Test
+ public void throw_ISE_if_host_for_random_port_cant_be_resolved() throws Exception{
+ NetworkUtils network = mock(NetworkUtils.class);
+ doThrow(new UnknownHostException("BOOM")).when(network).toInetAddress(anyString());
+ completeValidSettings();
+ StartableHazelcastMember underTest = new StartableHazelcastMember(settings.asConfig(), network);
+
+ expectedException.expect(IllegalStateException.class);
+ expectedException.expectMessage("Can not resolve address ");
+
+ underTest.start();
+
+ verifyStopped(underTest);
+ }
+
+ private void completeValidSettings() {
+ settings.setProperty("sonar.cluster.name", "foo");
+ settings.setProperty("sonar.cluster.node.host", loopback);
+ settings.setProperty("sonar.cluster.node.name", "bar");
+ settings.setProperty("sonar.cluster.node.type", "application");
+ settings.setProperty("process.key", "ce");
+ }
+
+ private static void verifyStopped(StartableHazelcastMember member) {
+ expectNpe(member::getMemberUuids);
+ expectNpe(member::getCluster);
+ expectNpe(member::getUuid);
+ }
+
+ private static void expectNpe(Supplier supplier) {
+ try {
+ supplier.get();
+ fail();
+ } catch (NullPointerException e) {
+ }
+ }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/health/ClusterHealthTest.java b/server/sonar-server/src/test/java/org/sonar/server/health/ClusterHealthTest.java
index 8a8d918c90d..99ed8271692 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/health/ClusterHealthTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/health/ClusterHealthTest.java
@@ -19,7 +19,9 @@
*/
package org.sonar.server.health;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
@@ -100,6 +102,17 @@ public class ClusterHealthTest {
assertThat(underTest.toString()).isEqualTo("ClusterHealth{health=" + health + ", nodes=" + nodeHealths + "}");
}
+ @Test
+ public void test_getNodeHealth() {
+ Health health = randomHealth();
+ Set<NodeHealth> nodeHealths = new HashSet<>(Arrays.asList(newNodeHealth("foo"), newNodeHealth("bar")));
+
+ ClusterHealth underTest = new ClusterHealth(health, nodeHealths);
+
+ assertThat(underTest.getNodeHealth("does_not_exist")).isEmpty();
+ assertThat(underTest.getNodeHealth("bar")).isPresent();
+ }
+
private Health randomHealth() {
Health.Builder healthBuilder = Health.newHealthCheckBuilder();
healthBuilder.setStatus(Health.Status.values()[random.nextInt(Health.Status.values().length)]);
@@ -120,4 +133,17 @@ public class ClusterHealthTest {
.build())
.build()).collect(Collectors.toSet());
}
+
+ private static NodeHealth newNodeHealth(String nodeName) {
+ return NodeHealth.newNodeHealthBuilder()
+ .setStatus(NodeHealth.Status.YELLOW)
+ .setDetails(NodeDetails.newNodeDetailsBuilder()
+ .setType(NodeDetails.Type.APPLICATION)
+ .setName(nodeName)
+ .setHost(randomAlphanumeric(4))
+ .setPort(3000)
+ .setStartedAt(1_000L)
+ .build())
+ .build();
+ }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/StandaloneSystemSectionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/StandaloneSystemSectionTest.java
index ea5f52d1054..33fdb132a4c 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/StandaloneSystemSectionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/platform/monitoring/StandaloneSystemSectionTest.java
@@ -30,14 +30,11 @@ import org.sonar.api.utils.log.LoggerLevel;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import org.sonar.server.authentication.IdentityProviderRepositoryRule;
import org.sonar.server.authentication.TestIdentityProvider;
-import org.sonar.server.health.Health;
-import org.sonar.server.health.TestStandaloneHealthChecker;
import org.sonar.server.platform.ServerId;
import org.sonar.server.platform.ServerIdLoader;
import org.sonar.server.platform.ServerLogging;
import org.sonar.server.user.SecurityRealmFactory;
-import static java.util.Arrays.asList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -57,11 +54,10 @@ public class StandaloneSystemSectionTest {
private ServerIdLoader serverIdLoader = mock(ServerIdLoader.class);
private ServerLogging serverLogging = mock(ServerLogging.class);
private SecurityRealmFactory securityRealmFactory = mock(SecurityRealmFactory.class);
- private TestStandaloneHealthChecker healthChecker = new TestStandaloneHealthChecker();
private OfficialDistribution officialDistribution = mock(OfficialDistribution.class);
private StandaloneSystemSection underTest = new StandaloneSystemSection(settings.asConfig(), securityRealmFactory, identityProviderRepository, server,
- serverLogging, serverIdLoader, officialDistribution, healthChecker);
+ serverLogging, serverIdLoader, officialDistribution);
@Before
public void setUp() throws Exception {
@@ -193,19 +189,6 @@ public class StandaloneSystemSectionTest {
}
@Test
- public void return_health() {
- healthChecker.setHealth(Health.newHealthCheckBuilder()
- .setStatus(Health.Status.YELLOW)
- .addCause("foo")
- .addCause("bar")
- .build());
-
- ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
- 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/ws/InfoActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/platform/ws/InfoActionTest.java
index 9c02608fddd..9e92b6205c7 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
@@ -29,6 +29,7 @@ import org.sonar.ce.http.CeHttpClientImpl;
import org.sonar.process.systeminfo.SystemInfoSection;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.health.TestStandaloneHealthChecker;
import org.sonar.server.telemetry.TelemetryData;
import org.sonar.server.telemetry.TelemetryDataLoader;
import org.sonar.server.tester.UserSessionRule;
@@ -51,9 +52,10 @@ public class InfoActionTest {
private SystemInfoSection section1 = mock(SystemInfoSection.class);
private SystemInfoSection section2 = mock(SystemInfoSection.class);
private CeHttpClient ceHttpClient = mock(CeHttpClientImpl.class, Mockito.RETURNS_MOCKS);
+ private TestStandaloneHealthChecker healthChecker = new TestStandaloneHealthChecker();
private TelemetryDataLoader statistics = mock(TelemetryDataLoader.class);
- private InfoAction underTest = new InfoAction(userSessionRule, ceHttpClient, statistics, section1, section2);
+ private InfoAction underTest = new InfoAction(userSessionRule, ceHttpClient, healthChecker, statistics, section1, section2);
private WsActionTester ws = new WsActionTester(underTest);
@Test
@@ -100,7 +102,7 @@ public class InfoActionTest {
TestResponse response = ws.newRequest().execute();
// response does not contain empty "Section Three"
verify(statistics).load();
- assertThat(response.getInput()).isEqualTo("{\"Section One\":{\"foo\":\"bar\"},\"Section Two\":{\"one\":1,\"two\":2}," +
+ assertThat(response.getInput()).isEqualTo("{\"Health\":\"GREEN\",\"Health Causes\":[],\"Section One\":{\"foo\":\"bar\"},\"Section Two\":{\"one\":1,\"two\":2}," +
"\"Statistics\":{\"plugins\":{},\"userCount\":0,\"projectCount\":0,\"lines\":0,\"ncloc\":0,\"projectCountByLanguage\":{},\"nclocByLanguage\":{}}}");
}
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 593619663da..179c09bd863 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
@@ -26,6 +26,8 @@ import org.sonar.ce.http.CeHttpClient;
import org.sonar.ce.http.CeHttpClientImpl;
import org.sonar.server.app.ProcessCommandWrapper;
import org.sonar.server.app.RestartFlagHolder;
+import org.sonar.server.health.HealthChecker;
+import org.sonar.server.health.TestStandaloneHealthChecker;
import org.sonar.server.platform.Platform;
import org.sonar.server.platform.WebServer;
import org.sonar.server.telemetry.TelemetryDataLoader;
@@ -37,13 +39,14 @@ import static org.mockito.Mockito.mock;
public class SystemWsTest {
- CeHttpClient ceHttpClient = mock(CeHttpClientImpl.class);
+ private CeHttpClient ceHttpClient = mock(CeHttpClientImpl.class);
+ private HealthChecker healthChecker = new TestStandaloneHealthChecker();
@Test
public void define() {
RestartAction action1 = new RestartAction(mock(UserSession.class), mock(Configuration.class), mock(Platform.class), mock(ProcessCommandWrapper.class),
mock(RestartFlagHolder.class), mock(WebServer.class));
- InfoAction action2 = new InfoAction(new AnonymousMockUserSession(), ceHttpClient, mock(TelemetryDataLoader.class));
+ InfoAction action2 = new InfoAction(new AnonymousMockUserSession(), ceHttpClient, healthChecker, mock(TelemetryDataLoader.class));
SystemWs ws = new SystemWs(action1, action2);
WebService.Context context = new WebService.Context();
diff --git a/server/sonar-web/src/main/js/api/system.ts b/server/sonar-web/src/main/js/api/system.ts
index df9da694e40..18851e79091 100644
--- a/server/sonar-web/src/main/js/api/system.ts
+++ b/server/sonar-web/src/main/js/api/system.ts
@@ -36,21 +36,26 @@ export enum HealthType {
GREEN = 'GREEN'
}
-export interface HealthCause extends SysValueObject {
- message: string;
-}
-
export interface NodeInfo extends SysValueObject {
- Name: string;
+ 'Compute Engine Logging': { 'Logs Level': string };
Health: HealthType;
- 'Health Causes': HealthCause[];
- 'Logs Level': string;
+ 'Health Causes': string[];
+ Name: string;
+ 'Web Logging': { 'Logs Level': string };
}
export interface SysInfo extends SysValueObject {
- Cluster: boolean;
Health: HealthType;
- 'Health Causes': HealthCause[];
+ 'Health Causes': string[];
+ System: {
+ 'High Availability': boolean;
+ 'Logs Level': string;
+ };
+}
+
+export interface ClusterSysInfo extends SysInfo {
+ 'Application Nodes': NodeInfo[];
+ 'Search Nodes': NodeInfo[];
}
export function setLogLevel(level: string): Promise<void | Response> {
diff --git a/server/sonar-web/src/main/js/apps/system/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/system/__tests__/utils-test.ts
index 0c550fd943f..b1e915f0370 100644
--- a/server/sonar-web/src/main/js/apps/system/__tests__/utils-test.ts
+++ b/server/sonar-web/src/main/js/apps/system/__tests__/utils-test.ts
@@ -18,6 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as u from '../utils';
+import { ClusterSysInfo, SysInfo } from '../../../api/system';
describe('parseQuery', () => {
it('should correctly parse the expand array', () => {
@@ -44,16 +45,26 @@ describe('groupSections', () => {
describe('getSystemLogsLevel', () => {
it('should correctly return log level for standalone mode', () => {
- expect(u.getSystemLogsLevel({ 'Logs Level': 'FOO' } as u.StandaloneSysInfo)).toBe('FOO');
- expect(u.getSystemLogsLevel({} as u.StandaloneSysInfo)).toBe('INFO');
+ expect(u.getSystemLogsLevel({ System: { 'Logs Level': 'FOO' } } as SysInfo)).toBe('FOO');
+ expect(u.getSystemLogsLevel({} as SysInfo)).toBe('INFO');
expect(u.getSystemLogsLevel()).toBe('INFO');
});
+
it('should return the worst log level for cluster mode', () => {
expect(
u.getSystemLogsLevel({
- Cluster: true,
- 'Application Nodes': [{ 'Logs Level': 'INFO' }, { 'Logs Level': 'DEBUG' }]
- } as u.ClusterSysInfo)
+ System: { 'High Availability': true },
+ 'Application Nodes': [
+ {
+ 'Compute Engine Logging': { 'Logs Level': 'DEBUG' },
+ 'Web Logging': { 'Logs Level': 'INFO' }
+ },
+ {
+ 'Compute Engine Logging': { 'Logs Level': 'INFO' },
+ 'Web Logging': { 'Logs Level': 'INFO' }
+ }
+ ]
+ } as ClusterSysInfo)
).toBe('DEBUG');
});
});
diff --git a/server/sonar-web/src/main/js/apps/system/components/App.tsx b/server/sonar-web/src/main/js/apps/system/components/App.tsx
index 1cd3752de88..38679882597 100644
--- a/server/sonar-web/src/main/js/apps/system/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/App.tsx
@@ -24,16 +24,8 @@ import ClusterSysInfos from './ClusterSysInfos';
import PageHeader from './PageHeader';
import StandaloneSysInfos from './StandaloneSysInfos';
import { translate } from '../../../helpers/l10n';
-import { getSystemInfo, SysInfo } from '../../../api/system';
-import {
- ClusterSysInfo,
- getSystemLogsLevel,
- isCluster,
- parseQuery,
- Query,
- serializeQuery,
- StandaloneSysInfo
-} from '../utils';
+import { ClusterSysInfo, getSystemInfo, SysInfo } from '../../../api/system';
+import { getSystemLogsLevel, isCluster, parseQuery, Query, serializeQuery } from '../utils';
import { RawQuery } from '../../../helpers/query';
import '../styles.css';
@@ -114,7 +106,7 @@ export default class App extends React.PureComponent<Props, State> {
return (
<StandaloneSysInfos
expandedCards={query.expandedCards}
- sysInfoData={sysInfoData as StandaloneSysInfo}
+ sysInfoData={sysInfoData}
toggleCard={this.toggleSysInfoCards}
/>
);
diff --git a/server/sonar-web/src/main/js/apps/system/components/ChangeLogLevelForm.tsx b/server/sonar-web/src/main/js/apps/system/components/ChangeLogLevelForm.tsx
index 6118fe2d956..7de208bd4f6 100644
--- a/server/sonar-web/src/main/js/apps/system/components/ChangeLogLevelForm.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/ChangeLogLevelForm.tsx
@@ -49,7 +49,7 @@ export default class ChangeLogLevelForm extends React.PureComponent<Props, State
handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
event.preventDefault();
const { newLevel } = this.state;
- if (!this.state.updating && newLevel !== this.props.logLevel) {
+ if (!this.state.updating) {
this.setState({ updating: true });
setLogLevel(newLevel).then(
() => this.props.onChange(newLevel),
@@ -64,7 +64,6 @@ export default class ChangeLogLevelForm extends React.PureComponent<Props, State
render() {
const { updating, newLevel } = this.state;
const header = translate('system.set_log_level');
- const disableSubmit = updating || newLevel === this.props.logLevel;
return (
<Modal
isOpen={true}
@@ -100,7 +99,7 @@ export default class ChangeLogLevelForm extends React.PureComponent<Props, State
</div>
<div className="modal-foot">
{updating && <i className="spinner spacer-right" />}
- <button disabled={disableSubmit} id="set-log-level-submit">
+ <button disabled={updating} id="set-log-level-submit">
{translate('save')}
</button>
<a href="#" id="set-log-level-cancel" onClick={this.handleCancelClick}>
diff --git a/server/sonar-web/src/main/js/apps/system/components/ClusterSysInfos.tsx b/server/sonar-web/src/main/js/apps/system/components/ClusterSysInfos.tsx
index cb3000dea32..54c70b1999c 100644
--- a/server/sonar-web/src/main/js/apps/system/components/ClusterSysInfos.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/ClusterSysInfos.tsx
@@ -21,8 +21,8 @@ import * as React from 'react';
import { sortBy } from 'lodash';
import HealthCard from './info-items/HealthCard';
import { translate } from '../../../helpers/l10n';
+import { ClusterSysInfo } from '../../../api/system';
import {
- ClusterSysInfo,
getAppNodes,
getHealth,
getHealthCauses,
diff --git a/server/sonar-web/src/main/js/apps/system/components/StandaloneSysInfos.tsx b/server/sonar-web/src/main/js/apps/system/components/StandaloneSysInfos.tsx
index 4ed444cc66d..69ddc3cbfab 100644
--- a/server/sonar-web/src/main/js/apps/system/components/StandaloneSysInfos.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/StandaloneSysInfos.tsx
@@ -20,18 +20,18 @@
import * as React from 'react';
import { map } from 'lodash';
import HealthCard from './info-items/HealthCard';
+import { SysInfo } from '../../../api/system';
import {
getHealth,
getHealthCauses,
getStandaloneMainSections,
getStandaloneSecondarySections,
- ignoreInfoFields,
- StandaloneSysInfo
+ ignoreInfoFields
} from '../utils';
interface Props {
expandedCards: string[];
- sysInfoData: StandaloneSysInfo;
+ sysInfoData: SysInfo;
toggleCard: (toggledCard: string) => void;
}
diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/ClusterSysInfos-test.tsx b/server/sonar-web/src/main/js/apps/system/components/__tests__/ClusterSysInfos-test.tsx
index 21c60cbd6fc..c2e892abb5d 100644
--- a/server/sonar-web/src/main/js/apps/system/components/__tests__/ClusterSysInfos-test.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/ClusterSysInfos-test.tsx
@@ -20,20 +20,33 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import ClusterSysInfos from '../ClusterSysInfos';
-import { HealthType } from '../../../../api/system';
-import { ClusterSysInfo } from '../../utils';
+import { ClusterSysInfo, HealthType } from '../../../../api/system';
const sysInfoData: ClusterSysInfo = {
- Cluster: true,
Health: HealthType.RED,
- Name: 'Foo',
- 'Health Causes': [{ message: 'Database down' }],
+ 'Health Causes': ['Database down'],
'Application Nodes': [
- { Name: 'Bar', Health: HealthType.GREEN, 'Health Causes': [], 'Logs Level': 'INFO' }
+ {
+ Name: 'Bar',
+ Health: HealthType.GREEN,
+ 'Health Causes': [],
+ 'Compute Engine Logging': { 'Logs Level': 'INFO' },
+ 'Web Logging': { 'Logs Level': 'INFO' }
+ }
],
'Search Nodes': [
- { Name: 'Baz', Health: HealthType.YELLOW, 'Health Causes': [], 'Logs Level': 'INFO' }
- ]
+ {
+ Name: 'Baz',
+ Health: HealthType.YELLOW,
+ 'Health Causes': [],
+ 'Compute Engine Logging': { 'Logs Level': 'INFO' },
+ 'Web Logging': { 'Logs Level': 'INFO' }
+ }
+ ],
+ System: {
+ 'High Availability': true,
+ 'Logs Level': 'INFO'
+ }
};
it('should render correctly', () => {
@@ -42,9 +55,27 @@ it('should render correctly', () => {
sysInfoData: {
...sysInfoData,
'Application Nodes': [
- { Name: 'Foo', Health: HealthType.GREEN, 'Health Causes': [], 'Logs Level': 'INFO' },
- { Name: 'Bar', Health: HealthType.RED, 'Health Causes': [], 'Logs Level': 'DEBUG' },
- { Name: 'Baz', Health: HealthType.YELLOW, 'Health Causes': [], 'Logs Level': 'TRACE' }
+ {
+ Name: 'Foo',
+ Health: HealthType.GREEN,
+ 'Health Causes': [],
+ 'Compute Engine Logging': { 'Logs Level': 'INFO' },
+ 'Web Logging': { 'Logs Level': 'INFO' }
+ },
+ {
+ Name: 'Bar',
+ Health: HealthType.RED,
+ 'Health Causes': [],
+ 'Compute Engine Logging': { 'Logs Level': 'INFO' },
+ 'Web Logging': { 'Logs Level': 'DEBUG' }
+ },
+ {
+ Name: 'Baz',
+ Health: HealthType.YELLOW,
+ 'Health Causes': [],
+ 'Compute Engine Logging': { 'Logs Level': 'TRACE' },
+ 'Web Logging': { 'Logs Level': 'DEBUG' }
+ }
]
}
}).find('HealthCard')
diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/StandaloneSysInfos-test.tsx b/server/sonar-web/src/main/js/apps/system/components/__tests__/StandaloneSysInfos-test.tsx
index c70202e3219..220cdb85ef1 100644
--- a/server/sonar-web/src/main/js/apps/system/components/__tests__/StandaloneSysInfos-test.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/StandaloneSysInfos-test.tsx
@@ -20,18 +20,18 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import StandaloneSysInfos from '../StandaloneSysInfos';
-import { HealthType } from '../../../../api/system';
-import { StandaloneSysInfo } from '../../utils';
+import { HealthType, SysInfo } from '../../../../api/system';
-const sysInfoData: StandaloneSysInfo = {
- Cluster: true,
+const sysInfoData: SysInfo = {
Health: HealthType.RED,
- 'Logs Level': 'DEBUG',
- Name: 'Foo',
- 'Health Causes': [{ message: 'Database down' }],
+ 'Health Causes': ['Database down'],
'Web JVM': { 'Max Memory': '2Gb' },
'Compute Engine': { Pending: 4 },
- Elasticsearch: { 'Number of Nodes': 1 }
+ Search: { 'Number of Nodes': 1 },
+ System: {
+ 'High Availability': true,
+ 'Logs Level': 'DEBUG'
+ }
};
it('should render correctly', () => {
diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ChangeLogLevelForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ChangeLogLevelForm-test.tsx.snap
index eeaa775462d..4759423740e 100644
--- a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ChangeLogLevelForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ChangeLogLevelForm-test.tsx.snap
@@ -97,7 +97,7 @@ exports[`should display some warning messages for non INFO levels 1`] = `
className="modal-foot"
>
<button
- disabled={true}
+ disabled={false}
id="set-log-level-submit"
>
save
@@ -206,7 +206,7 @@ exports[`should render correctly 1`] = `
className="modal-foot"
>
<button
- disabled={true}
+ disabled={false}
id="set-log-level-submit"
>
save
diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ClusterSysInfos-test.tsx.snap b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ClusterSysInfos-test.tsx.snap
index abd7d3a63ac..6db92bdf46b 100644
--- a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ClusterSysInfos-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ClusterSysInfos-test.tsx.snap
@@ -7,9 +7,7 @@ exports[`should support more than two nodes 1`] = `
health="RED"
healthCauses={
Array [
- Object {
- "message": "Database down",
- },
+ "Database down",
]
}
name="System"
@@ -17,7 +15,8 @@ exports[`should support more than two nodes 1`] = `
open={true}
sysInfoData={
Object {
- "Name": "Foo",
+ "High Availability": true,
+ "Logs Level": "INFO",
}
}
/>
@@ -34,8 +33,12 @@ exports[`should support more than two nodes 1`] = `
open={false}
sysInfoData={
Object {
- "Logs Level": "INFO",
- "Name": "Bar",
+ "Compute Engine Logging": Object {
+ "Logs Level": "INFO",
+ },
+ "Web Logging": Object {
+ "Logs Level": "INFO",
+ },
}
}
/>
@@ -52,8 +55,12 @@ exports[`should support more than two nodes 1`] = `
open={false}
sysInfoData={
Object {
- "Logs Level": "INFO",
- "Name": "Baz",
+ "Compute Engine Logging": Object {
+ "Logs Level": "INFO",
+ },
+ "Web Logging": Object {
+ "Logs Level": "INFO",
+ },
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/StandaloneSysInfos-test.tsx.snap b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/StandaloneSysInfos-test.tsx.snap
index f4961aeac1e..b7a2d4285c1 100644
--- a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/StandaloneSysInfos-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/StandaloneSysInfos-test.tsx.snap
@@ -7,9 +7,7 @@ exports[`should render correctly 1`] = `
health="RED"
healthCauses={
Array [
- Object {
- "message": "Database down",
- },
+ "Database down",
]
}
name="System"
@@ -17,8 +15,8 @@ exports[`should render correctly 1`] = `
open={false}
sysInfoData={
Object {
+ "High Availability": true,
"Logs Level": "DEBUG",
- "Name": "Foo",
}
}
/>
@@ -28,11 +26,9 @@ exports[`should render correctly 1`] = `
open={false}
sysInfoData={
Object {
- "Web Database Connectivity": undefined,
"Web JVM": Object {
"Max Memory": "2Gb",
},
- "Web JVM Properties": undefined,
}
}
/>
@@ -42,9 +38,9 @@ exports[`should render correctly 1`] = `
open={true}
sysInfoData={
Object {
- "Compute Engine JVM": undefined,
- "Compute Engine JVM Properties": undefined,
- "Pending": 4,
+ "Compute Engine": Object {
+ "Pending": 4,
+ },
}
}
/>
@@ -54,11 +50,9 @@ exports[`should render correctly 1`] = `
open={false}
sysInfoData={
Object {
- "Elasticsearch": Object {
+ "Search": Object {
"Number of Nodes": 1,
},
- "Search JVM": undefined,
- "Search JVM Properties": undefined,
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCard.tsx b/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCard.tsx
index 459f26ee721..ff49fc75a83 100644
--- a/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCard.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCard.tsx
@@ -23,14 +23,14 @@ import { map } from 'lodash';
import HealthItem from './HealthItem';
import OpenCloseIcon from '../../../../components/icons-components/OpenCloseIcon';
import Section from './Section';
-import { HealthType, HealthCause, SysValueObject } from '../../../../api/system';
+import { HealthType, SysValueObject } from '../../../../api/system';
import { LOGS_LEVELS, groupSections, getLogsLevel } from '../../utils';
import { translate } from '../../../../helpers/l10n';
interface Props {
biggerHealth?: boolean;
health?: HealthType;
- healthCauses?: HealthCause[];
+ healthCauses?: string[];
onClick: (toggledCard: string) => void;
open: boolean;
name: string;
diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCauseItem.tsx b/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCauseItem.tsx
index 49b22b717bb..7d34624a709 100644
--- a/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCauseItem.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCauseItem.tsx
@@ -19,12 +19,12 @@
*/
import * as React from 'react';
import * as classNames from 'classnames';
-import { HealthCause, HealthType } from '../../../../api/system';
+import { HealthType } from '../../../../api/system';
interface Props {
className?: string;
health: HealthType;
- healthCause: HealthCause;
+ healthCause: string;
}
export default function HealthCauseItem({ className, health, healthCause }: Props) {
@@ -35,7 +35,7 @@ export default function HealthCauseItem({ className, health, healthCause }: Prop
health === HealthType.RED ? 'alert-danger' : 'alert-warning',
className
)}>
- {healthCause.message}
+ {healthCause}
</span>
);
}
diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/HealthItem.tsx b/server/sonar-web/src/main/js/apps/system/components/info-items/HealthItem.tsx
index 86618c34c8a..2edc10805e0 100644
--- a/server/sonar-web/src/main/js/apps/system/components/info-items/HealthItem.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/info-items/HealthItem.tsx
@@ -21,13 +21,13 @@ import * as React from 'react';
import * as classNames from 'classnames';
import HealthCauseItem from './HealthCauseItem';
import StatusIndicator from '../../../../components/common/StatusIndicator';
-import { HealthType, HealthCause } from '../../../../api/system';
+import { HealthType } from '../../../../api/system';
interface Props {
biggerHealth?: boolean;
className?: string;
health: HealthType;
- healthCauses?: HealthCause[];
+ healthCauses?: string[];
}
export default function HealthItem({ biggerHealth, className, health, healthCauses }: Props) {
diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCard-test.tsx b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCard-test.tsx
index 98b33bd31ee..933510b929f 100644
--- a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCard-test.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCard-test.tsx
@@ -59,7 +59,7 @@ function getShallowWrapper(props = {}) {
<HealthCard
biggerHealth={false}
health={HealthType.RED}
- healthCauses={[{ message: 'foo' }]}
+ healthCauses={['foo']}
name="Foobar"
onClick={() => {}}
open={false}
diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCauseItem-test.tsx b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCauseItem-test.tsx
index 24504f09a91..319d069cae5 100644
--- a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCauseItem-test.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCauseItem-test.tsx
@@ -23,10 +23,8 @@ import HealthCauseItem from '../HealthCauseItem';
import { HealthType } from '../../../../../api/system';
it('should render correctly', () => {
+ expect(shallow(<HealthCauseItem health={HealthType.RED} healthCause="foo" />)).toMatchSnapshot();
expect(
- shallow(<HealthCauseItem health={HealthType.RED} healthCause={{ message: 'foo' }} />)
- ).toMatchSnapshot();
- expect(
- shallow(<HealthCauseItem health={HealthType.YELLOW} healthCause={{ message: 'foo' }} />)
+ shallow(<HealthCauseItem health={HealthType.YELLOW} healthCause="foo" />)
).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthItem-test.tsx b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthItem-test.tsx
index 9f1bd198352..7f21d999a4e 100644
--- a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthItem-test.tsx
+++ b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthItem-test.tsx
@@ -24,26 +24,19 @@ import { HealthType } from '../../../../../api/system';
it('should render correctly', () => {
expect(
- shallow(
- <HealthItem biggerHealth={true} health={HealthType.RED} healthCauses={[{ message: 'foo' }]} />
- )
+ shallow(<HealthItem biggerHealth={true} health={HealthType.RED} healthCauses={['foo']} />)
).toMatchSnapshot();
});
it('should not render health causes', () => {
expect(
- shallow(<HealthItem health={HealthType.GREEN} healthCauses={[{ message: 'foo' }]} />)
+ shallow(<HealthItem health={HealthType.GREEN} healthCauses={['foo']} />)
).toMatchSnapshot();
expect(shallow(<HealthItem health={HealthType.YELLOW} healthCauses={[]} />)).toMatchSnapshot();
});
it('should render multiple health causes', () => {
expect(
- shallow(
- <HealthItem
- health={HealthType.YELLOW}
- healthCauses={[{ message: 'foo' }, { message: 'bar' }]}
- />
- )
+ shallow(<HealthItem health={HealthType.YELLOW} healthCauses={['foo', 'bar']} />)
).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/__snapshots__/HealthCard-test.tsx.snap b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/__snapshots__/HealthCard-test.tsx.snap
index 7390ef8020e..6c054721b70 100644
--- a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/__snapshots__/HealthCard-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/__snapshots__/HealthCard-test.tsx.snap
@@ -31,9 +31,7 @@ exports[`should display the sysinfo detail 1`] = `
health="RED"
healthCauses={
Array [
- Object {
- "message": "foo",
- },
+ "foo",
]
}
/>
@@ -69,9 +67,7 @@ exports[`should render correctly 1`] = `
health="RED"
healthCauses={
Array [
- Object {
- "message": "foo",
- },
+ "foo",
]
}
/>
@@ -102,9 +98,7 @@ exports[`should show a main section and multiple sub sections 1`] = `
health="RED"
healthCauses={
Array [
- Object {
- "message": "foo",
- },
+ "foo",
]
}
/>
diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/__snapshots__/HealthItem-test.tsx.snap b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/__snapshots__/HealthItem-test.tsx.snap
index f962437404c..eafb250bdd1 100644
--- a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/__snapshots__/HealthItem-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/__snapshots__/HealthItem-test.tsx.snap
@@ -27,11 +27,7 @@ exports[`should render correctly 1`] = `
<HealthCauseItem
className="spacer-right"
health="RED"
- healthCause={
- Object {
- "message": "foo",
- }
- }
+ healthCause="foo"
/>
<StatusIndicator
color="red"
@@ -47,20 +43,12 @@ exports[`should render multiple health causes 1`] = `
<HealthCauseItem
className="spacer-right"
health="YELLOW"
- healthCause={
- Object {
- "message": "foo",
- }
- }
+ healthCause="foo"
/>
<HealthCauseItem
className="spacer-right"
health="YELLOW"
- healthCause={
- Object {
- "message": "bar",
- }
- }
+ healthCause="bar"
/>
<StatusIndicator
color="yellow"
diff --git a/server/sonar-web/src/main/js/apps/system/utils.ts b/server/sonar-web/src/main/js/apps/system/utils.ts
index ae8818edf9d..5d98c9e74f8 100644
--- a/server/sonar-web/src/main/js/apps/system/utils.ts
+++ b/server/sonar-web/src/main/js/apps/system/utils.ts
@@ -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.
*/
-import { each, omit, memoize, sortBy } from 'lodash';
+import { each, memoize, omit, omitBy, pickBy, sortBy } from 'lodash';
import {
cleanQuery,
parseAsArray,
@@ -26,7 +26,7 @@ import {
serializeStringArray
} from '../../helpers/query';
import {
- HealthCause,
+ ClusterSysInfo,
HealthType,
NodeInfo,
SysInfo,
@@ -38,45 +38,64 @@ export interface Query {
expandedCards: string[];
}
-export interface ClusterSysInfo extends SysInfo {
- 'Application Nodes': NodeInfo[];
- 'Search Nodes': NodeInfo[];
-}
-
-export interface StandaloneSysInfo extends SysInfo {
- 'Logs Level': string;
-}
-
export const LOGS_LEVELS = ['INFO', 'DEBUG', 'TRACE'];
+export const HA_FIELD = 'High Availability';
export const HEALTH_FIELD = 'Health';
export const HEALTHCAUSES_FIELD = 'Health Causes';
export function ignoreInfoFields(sysInfoObject: SysValueObject): SysValueObject {
- return omit(sysInfoObject, ['Cluster', HEALTH_FIELD, HEALTHCAUSES_FIELD]);
+ return omit(sysInfoObject, [HEALTH_FIELD, HEALTHCAUSES_FIELD, 'Name', 'Settings']);
}
export function getHealth(sysInfoObject: SysValueObject): HealthType {
return sysInfoObject[HEALTH_FIELD] as HealthType;
}
-export function getHealthCauses(sysInfoObject: SysValueObject): HealthCause[] {
- return sysInfoObject[HEALTHCAUSES_FIELD] as HealthCause[];
+export function getHealthCauses(sysInfoObject: SysValueObject): string[] {
+ return sysInfoObject[HEALTHCAUSES_FIELD] as string[];
}
export function getLogsLevel(sysInfoObject: SysValueObject): string {
+ if (sysInfoObject['Web Logging']) {
+ return sortBy(
+ [
+ (sysInfoObject as NodeInfo)['Compute Engine Logging']['Logs Level'],
+ (sysInfoObject as NodeInfo)['Web Logging']['Logs Level']
+ ],
+ logLevel => LOGS_LEVELS.indexOf(logLevel)
+ )[1];
+ }
+ if (sysInfoObject['System']) {
+ return (sysInfoObject as SysInfo)['System']['Logs Level'];
+ }
return (sysInfoObject['Logs Level'] || LOGS_LEVELS[0]) as string;
}
+export function getAppNodes(sysInfoData: ClusterSysInfo): NodeInfo[] {
+ return sysInfoData['Application Nodes'];
+}
+
+export function getSearchNodes(sysInfoData: ClusterSysInfo): NodeInfo[] {
+ return sysInfoData['Search Nodes'];
+}
+
+export function isCluster(sysInfoData?: SysInfo): boolean {
+ return (
+ sysInfoData != undefined && sysInfoData['System'] && sysInfoData['System'][HA_FIELD] === true
+ );
+}
+
export function getSystemLogsLevel(sysInfoData?: SysInfo): string {
const defaultLevel = LOGS_LEVELS[0];
if (!sysInfoData) {
return defaultLevel;
}
if (isCluster(sysInfoData)) {
- const nodes = sortBy(getAppNodes(sysInfoData as ClusterSysInfo), node =>
- LOGS_LEVELS.indexOf(getLogsLevel(node))
+ const logLevels = sortBy(
+ getAppNodes(sysInfoData as ClusterSysInfo).map(getLogsLevel),
+ logLevel => LOGS_LEVELS.indexOf(logLevel)
);
- return nodes.length > 0 ? getLogsLevel(nodes[nodes.length - 1]) : defaultLevel;
+ return logLevels.length > 0 ? logLevels[logLevels.length - 1] : defaultLevel;
} else {
return getLogsLevel(sysInfoData);
}
@@ -87,51 +106,40 @@ export function getNodeName(nodeInfo: NodeInfo): string {
}
export function getClusterMainCardSection(sysInfoData: ClusterSysInfo): SysValueObject {
- return omit(sysInfoData, ['Application Nodes', 'Search Nodes', 'Settings', 'Statistics']);
-}
-
-export function getStandaloneMainSections(sysInfoData: StandaloneSysInfo): SysValueObject {
- return omit(sysInfoData, [
- 'Settings',
- 'Statistics',
- 'Compute Engine',
- 'Compute Engine JVM',
- 'Compute Engine JVM Properties',
- 'Elasticsearch',
- 'Search JVM',
- 'Search JVM Properties',
- 'Web Database Connectivity',
- 'Web JVM',
- 'Web JVM Properties'
- ]);
-}
-
-export function getStandaloneSecondarySections(sysInfoData: StandaloneSysInfo): SysInfoSection {
return {
- Web: {
- 'Web Database Connectivity': sysInfoData['Web Database Connectivity'],
- 'Web JVM': sysInfoData['Web JVM'],
- 'Web JVM Properties': sysInfoData['Web JVM Properties']
- },
- 'Compute Engine': {
- ...sysInfoData['Compute Engine'] as SysValueObject,
- 'Compute Engine JVM': sysInfoData['Compute Engine JVM'],
- 'Compute Engine JVM Properties': sysInfoData['Compute Engine JVM Properties']
- },
- Search: {
- Elasticsearch: sysInfoData['Elasticsearch'] as SysValueObject,
- 'Search JVM': sysInfoData['Search JVM'],
- 'Search JVM Properties': sysInfoData['Search JVM Properties']
- }
+ ...sysInfoData['System'],
+ ...omit(sysInfoData, [
+ 'Application Nodes',
+ 'Plugins',
+ 'Search Nodes',
+ 'Settings',
+ 'Statistics',
+ 'System'
+ ])
};
}
-export function getAppNodes(sysInfoData: ClusterSysInfo): NodeInfo[] {
- return sysInfoData['Application Nodes'];
+export function getStandaloneMainSections(sysInfoData: SysInfo): SysValueObject {
+ return {
+ ...sysInfoData['System'],
+ ...omitBy(
+ sysInfoData,
+ (value, key) =>
+ value == null ||
+ ['Plugins', 'Settings', 'Statistics', 'System'].includes(key) ||
+ key.startsWith('Compute Engine') ||
+ key.startsWith('Search') ||
+ key.startsWith('Web')
+ )
+ };
}
-export function getSearchNodes(sysInfoData: ClusterSysInfo): NodeInfo[] {
- return sysInfoData['Search Nodes'];
+export function getStandaloneSecondarySections(sysInfoData: SysInfo): SysInfoSection {
+ return {
+ Web: pickBy(sysInfoData, (_, key) => key.startsWith('Web')),
+ 'Compute Engine': pickBy(sysInfoData, (_, key) => key.startsWith('Compute Engine')),
+ Search: pickBy(sysInfoData, (_, key) => key.startsWith('Search'))
+ };
}
export function groupSections(sysInfoData: SysValueObject) {
@@ -147,18 +155,12 @@ export function groupSections(sysInfoData: SysValueObject) {
return { mainSection, sections };
}
-export function isCluster(sysInfoData?: SysInfo): boolean {
- return sysInfoData != undefined && sysInfoData['Cluster'] === true;
-}
+export const parseQuery = memoize((urlQuery: RawQuery): Query => ({
+ expandedCards: parseAsArray(urlQuery.expand, parseAsString)
+}));
-export const parseQuery = memoize((urlQuery: RawQuery): Query => {
- return {
- expandedCards: parseAsArray(urlQuery.expand, parseAsString)
- };
-});
-
-export const serializeQuery = memoize((query: Query): RawQuery => {
- return cleanQuery({
+export const serializeQuery = memoize((query: Query): RawQuery =>
+ cleanQuery({
expand: serializeStringArray(query.expandedCards)
- });
-});
+ })
+);
diff --git a/server/sonar-web/src/main/js/components/common/StatusIndicator.css b/server/sonar-web/src/main/js/components/common/StatusIndicator.css
index 26008838cd2..7e7aab81429 100644
--- a/server/sonar-web/src/main/js/components/common/StatusIndicator.css
+++ b/server/sonar-web/src/main/js/components/common/StatusIndicator.css
@@ -25,7 +25,7 @@
background-color: #d4333f;
}
-.sstatus-indicator.yellow {
+.status-indicator.yellow {
background-color: #eabe06;
}