import org.sonar.ce.configuration.CeConfigurationImpl;
import org.sonar.ce.log.CeLogging;
import org.sonar.core.platform.Module;
-import org.sonar.process.systeminfo.ProcessStateSystemInfo;
+import org.sonar.process.systeminfo.JvmStateSection;
import org.sonar.ce.monitoring.CeDatabaseMBeanImpl;
public class CeConfigurationModule extends Module {
CeConfigurationImpl.class,
CeLogging.class,
CeDatabaseMBeanImpl.class,
- new ProcessStateSystemInfo("Compute Engine State"));
+ new JvmStateSection("Compute Engine JVM State"));
}
}
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.ce.httpd.HttpAction;
-import org.sonar.process.systeminfo.ProcessStateSystemInfo;
+import org.sonar.process.systeminfo.JvmStateSection;
import org.sonar.process.systeminfo.SystemInfoSection;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
@Rule
public ExpectedException expectedException = ExpectedException.none();
- private SystemInfoSection stateProvider1 = new ProcessStateSystemInfo("state1");
- private SystemInfoSection stateProvider2 = new ProcessStateSystemInfo("state2");
+ private SystemInfoSection stateProvider1 = new JvmStateSection("state1");
+ private SystemInfoSection stateProvider2 = new JvmStateSection("state2");
private SystemInfoHttpAction underTest;
@Before
return members;
}
- void setAnswer(Member member, T answer) {
+ public void setAnswer(Member member, T answer) {
this.answers.put(member, answer);
}
- void setTimedOut(Member member) {
+ public void setTimedOut(Member member) {
this.timedOutMembers.add(member);
}
- void setFailed(Member member, Exception e) {
+ public void setFailed(Member member, Exception e) {
failedMembers.put(member, e);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.systeminfo;
+
+import java.util.Map;
+import java.util.Objects;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
+
+/**
+ * Dumps {@link System#getProperties()}
+ */
+public class JvmPropertiesSection implements SystemInfoSection {
+
+ private final String name;
+
+ public JvmPropertiesSection(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public ProtobufSystemInfo.Section toProtobuf() {
+ ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder();
+ protobuf.setName(name);
+
+ for (Map.Entry<Object, Object> systemProp : System.getProperties().entrySet()) {
+ if (systemProp.getValue() != null) {
+ setAttribute(protobuf, Objects.toString(systemProp.getKey()), Objects.toString(systemProp.getValue()));
+ }
+ }
+ return protobuf.build();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.systeminfo;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.MemoryUsage;
+import java.lang.management.ThreadMXBean;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
+
+/**
+ * Dumps state of JVM (memory, threads)
+ */
+public class JvmStateSection implements SystemInfoSection {
+ private static final long MEGABYTE = 1024L * 1024L;
+ private final String name;
+
+ public JvmStateSection(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public ProtobufSystemInfo.Section toProtobuf() {
+ return toProtobuf(ManagementFactory.getMemoryMXBean());
+ }
+
+ // Visible for testing
+ ProtobufSystemInfo.Section toProtobuf(MemoryMXBean memoryBean) {
+ ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder();
+ protobuf.setName(name);
+ MemoryUsage heap = memoryBean.getHeapMemoryUsage();
+ addAttributeInMb(protobuf, "Heap Committed (MB)", heap.getCommitted());
+ addAttributeInMb(protobuf, "Heap Init (MB)", heap.getInit());
+ addAttributeInMb(protobuf, "Heap Max (MB)", heap.getMax());
+ addAttributeInMb(protobuf, "Heap Used (MB)", heap.getUsed());
+ MemoryUsage nonHeap = memoryBean.getNonHeapMemoryUsage();
+ addAttributeInMb(protobuf, "Non Heap Committed (MB)", nonHeap.getCommitted());
+ addAttributeInMb(protobuf, "Non Heap Init (MB)", nonHeap.getInit());
+ addAttributeInMb(protobuf, "Non Heap Max (MB)", nonHeap.getMax());
+ addAttributeInMb(protobuf, "Non Heap Used (MB)", nonHeap.getUsed());
+ ThreadMXBean thread = ManagementFactory.getThreadMXBean();
+ setAttribute(protobuf, "Thread Count", thread.getThreadCount());
+
+ return protobuf.build();
+ }
+
+ private static void addAttributeInMb(ProtobufSystemInfo.Section.Builder protobuf, String key, long valueInBytes) {
+ if (valueInBytes >= 0L) {
+ setAttribute(protobuf, key, valueInBytes / MEGABYTE);
+ }
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.process.systeminfo;
-
-import java.lang.management.ManagementFactory;
-import java.lang.management.MemoryMXBean;
-import java.lang.management.MemoryUsage;
-import java.lang.management.ThreadMXBean;
-import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
-
-public class ProcessStateSystemInfo implements SystemInfoSection {
- private static final long MEGABYTE = 1024L * 1024L;
- private final String name;
-
- public ProcessStateSystemInfo(String name) {
- this.name = name;
- }
-
- @Override
- public ProtobufSystemInfo.Section toProtobuf() {
- return toProtobuf(ManagementFactory.getMemoryMXBean());
- }
-
- // Visible for testing
- ProtobufSystemInfo.Section toProtobuf(MemoryMXBean memoryBean) {
- ProtobufSystemInfo.Section.Builder builder = ProtobufSystemInfo.Section.newBuilder();
- builder.setName(name);
- MemoryUsage heap = memoryBean.getHeapMemoryUsage();
- addAttributeInMb(builder, "Heap Committed (MB)", heap.getCommitted());
- addAttributeInMb(builder, "Heap Init (MB)", heap.getInit());
- addAttributeInMb(builder, "Heap Max (MB)", heap.getMax());
- addAttributeInMb(builder, "Heap Used (MB)", heap.getUsed());
- MemoryUsage nonHeap = memoryBean.getNonHeapMemoryUsage();
- addAttributeInMb(builder, "Non Heap Committed (MB)", nonHeap.getCommitted());
- addAttributeInMb(builder, "Non Heap Init (MB)", nonHeap.getInit());
- addAttributeInMb(builder, "Non Heap Max (MB)", nonHeap.getMax());
- addAttributeInMb(builder, "Non Heap Used (MB)", nonHeap.getUsed());
- ThreadMXBean thread = ManagementFactory.getThreadMXBean();
- builder.addAttributesBuilder().setKey("Thread Count").setLongValue(thread.getThreadCount()).build();
- return builder.build();
- }
-
- private static void addAttributeInMb(ProtobufSystemInfo.Section.Builder builder, String key, long valueInBytes) {
- if (valueInBytes >= 0L) {
- builder.addAttributesBuilder().setKey(key).setLongValue(valueInBytes / MEGABYTE).build();
- }
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.systeminfo;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+public class SystemInfoUtils {
+
+ private SystemInfoUtils() {
+ // prevent instantiation
+ }
+
+ public static void setAttribute(ProtobufSystemInfo.Section.Builder section, String key, @Nullable String value) {
+ if (value != null) {
+ section.addAttributesBuilder()
+ .setKey(key)
+ .setStringValue(value)
+ .build();
+ }
+ }
+
+ public static void setAttribute(ProtobufSystemInfo.Section.Builder section, String key, boolean value) {
+ section.addAttributesBuilder()
+ .setKey(key)
+ .setBooleanValue(value)
+ .build();
+ }
+
+ public static void setAttribute(ProtobufSystemInfo.Section.Builder section, String key, long value) {
+ section.addAttributesBuilder()
+ .setKey(key)
+ .setLongValue(value)
+ .build();
+ }
+
+ @CheckForNull
+ public static ProtobufSystemInfo.Attribute attribute(ProtobufSystemInfo.Section section, String key) {
+ for (ProtobufSystemInfo.Attribute attribute : section.getAttributesList()) {
+ if (attribute.getKey().equals(key)) {
+ return attribute;
+ }
+ }
+ return null;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.systeminfo;
+
+import org.assertj.core.api.Assertions;
+import org.junit.Test;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.process.systeminfo.SystemInfoUtils.attribute;
+
+public class JvmPropertiesSectionTest {
+
+ private JvmPropertiesSection underTest = new JvmPropertiesSection("Web JVM Properties");
+
+ @Test
+ public void name_is_not_empty() {
+ assertThat(underTest.toProtobuf().getName()).isEqualTo("Web JVM Properties");
+ }
+
+ @Test
+ public void test_toProtobuf() {
+ ProtobufSystemInfo.Section section = underTest.toProtobuf();
+
+ Assertions.assertThat(attribute(section, "java.vm.vendor").getStringValue()).isNotEmpty();
+ Assertions.assertThat(attribute(section, "os.name").getStringValue()).isNotEmpty();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.process.systeminfo;
+
+import java.lang.management.MemoryMXBean;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class JvmStateSectionTest {
+
+ public static final String PROCESS_NAME = "the process name";
+
+ @Test
+ public void toSystemInfoSection() {
+ JvmStateSection underTest = new JvmStateSection(PROCESS_NAME);
+ ProtobufSystemInfo.Section section = underTest.toProtobuf();
+
+ assertThat(section.getName()).isEqualTo(PROCESS_NAME);
+ assertThat(section.getAttributesCount()).isGreaterThan(0);
+ assertThat(section.getAttributesList()).extracting("key").contains("Thread Count");
+ }
+
+ @Test
+ public void should_hide_attributes_without_values() {
+ MemoryMXBean memoryBean = mock(MemoryMXBean.class, Mockito.RETURNS_DEEP_STUBS);
+ when(memoryBean.getHeapMemoryUsage().getCommitted()).thenReturn(-1L);
+
+ JvmStateSection underTest = new JvmStateSection(PROCESS_NAME);
+ ProtobufSystemInfo.Section section = underTest.toProtobuf(memoryBean);
+
+ assertThat(section.getAttributesList()).extracting("key").doesNotContain("Heap Committed (MB)");
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.process.systeminfo;
-
-import java.lang.management.MemoryMXBean;
-import org.junit.Test;
-import org.mockito.Mockito;
-import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class ProcessStateSystemInfoTest {
-
- public static final String PROCESS_NAME = "the process name";
-
- @Test
- public void toSystemInfoSection() {
- ProcessStateSystemInfo underTest = new ProcessStateSystemInfo(PROCESS_NAME);
- ProtobufSystemInfo.Section section = underTest.toProtobuf();
-
- assertThat(section.getName()).isEqualTo(PROCESS_NAME);
- assertThat(section.getAttributesCount()).isGreaterThan(0);
- assertThat(section.getAttributesList()).extracting("key").contains("Thread Count");
- }
-
- @Test
- public void should_hide_attributes_without_values() {
- MemoryMXBean memoryBean = mock(MemoryMXBean.class, Mockito.RETURNS_DEEP_STUBS);
- when(memoryBean.getHeapMemoryUsage().getCommitted()).thenReturn(-1L);
-
- ProcessStateSystemInfo underTest = new ProcessStateSystemInfo(PROCESS_NAME);
- ProtobufSystemInfo.Section section = underTest.toProtobuf(memoryBean);
-
- assertThat(section.getAttributesList()).extracting("key").doesNotContain("Heap Committed (MB)");
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import org.picocontainer.Startable;
-import org.sonar.process.Jmx;
-
-/**
- * Base implementation of a {@link org.sonar.server.platform.monitoring.Monitor}
- * that is exported as a JMX bean
- */
-public abstract class BaseMonitorMBean implements Monitor, Startable {
-
- /**
- * Auto-registers to MBean server
- */
- @Override
- public void start() {
- Jmx.register(objectName(), this);
- }
-
- /**
- * Unregister, if needed
- */
- @Override
- public void stop() {
- Jmx.unregister(objectName());
- }
-
- String objectName() {
- return "SonarQube:name=" + name();
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import org.picocontainer.Startable;
+import org.sonar.process.Jmx;
+import org.sonar.process.systeminfo.SystemInfoSection;
+
+/**
+ * Base implementation of a {@link SystemInfoSection}
+ * that is exported as a JMX bean
+ */
+public abstract class BaseSectionMBean implements SystemInfoSection, Startable {
+
+ /**
+ * Auto-registers to MBean server
+ */
+ @Override
+ public void start() {
+ Jmx.register(objectName(), this);
+ }
+
+ /**
+ * Unregister, if needed
+ */
+ @Override
+ public void stop() {
+ Jmx.unregister(objectName());
+ }
+
+ String objectName() {
+ return "SonarQube:name=" + name();
+ }
+
+ /**
+ * Name of section in System Info page
+ */
+ abstract String name();
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.sql.Connection;
-import java.sql.DatabaseMetaData;
-import java.sql.SQLException;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import org.apache.commons.dbcp.BasicDataSource;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.server.platform.db.migration.version.DatabaseVersion;
-
-/**
- * Information about database and connection pool
- */
-public class DatabaseMonitor extends BaseMonitorMBean implements DatabaseMonitorMBean {
-
- private final DatabaseVersion dbVersion;
- private final DbClient dbClient;
-
- public DatabaseMonitor(DatabaseVersion dbVersion, DbClient dbClient) {
- this.dbVersion = dbVersion;
- this.dbClient = dbClient;
- }
-
- @Override
- public String name() {
- return "Database";
- }
-
- @Override
- public String getMigrationStatus() {
- return dbVersion.getStatus().name();
- }
-
- @Override
- public int getPoolActiveConnections() {
- return commonsDbcp().getNumActive();
- }
-
- @Override
- public int getPoolMaxActiveConnections() {
- return commonsDbcp().getMaxActive();
- }
-
- @Override
- public int getPoolIdleConnections() {
- return commonsDbcp().getNumIdle();
- }
-
- @Override
- public int getPoolMaxIdleConnections() {
- return commonsDbcp().getMaxIdle();
- }
-
- @Override
- public int getPoolMinIdleConnections() {
- return commonsDbcp().getMinIdle();
- }
-
- @Override
- public int getPoolInitialSize() {
- return commonsDbcp().getInitialSize();
- }
-
- @Override
- public long getPoolMaxWaitMillis() {
- return commonsDbcp().getMaxWait();
- }
-
- @Override
- public boolean getPoolRemoveAbandoned() {
- return commonsDbcp().getRemoveAbandoned();
- }
-
- @Override
- public int getPoolRemoveAbandonedTimeoutSeconds() {
- return commonsDbcp().getRemoveAbandonedTimeout();
- }
-
- @Override
- public Map<String, Object> attributes() {
- Map<String, Object> attributes = new LinkedHashMap<>();
- completeDbAttributes(attributes);
- completePoolAttributes(attributes);
- return attributes;
- }
-
- private void completePoolAttributes(Map<String, Object> attributes) {
- attributes.put("Pool Active Connections", getPoolActiveConnections());
- attributes.put("Pool Max Connections", getPoolMaxActiveConnections());
- attributes.put("Pool Initial Size", getPoolInitialSize());
- attributes.put("Pool Idle Connections", getPoolIdleConnections());
- attributes.put("Pool Min Idle Connections", getPoolMinIdleConnections());
- attributes.put("Pool Max Idle Connections", getPoolMaxIdleConnections());
- attributes.put("Pool Max Wait (ms)", getPoolMaxWaitMillis());
- attributes.put("Pool Remove Abandoned", getPoolRemoveAbandoned());
- attributes.put("Pool Remove Abandoned Timeout (seconds)", getPoolRemoveAbandonedTimeoutSeconds());
- }
-
- private BasicDataSource commonsDbcp() {
- return (BasicDataSource) dbClient.getDatabase().getDataSource();
- }
-
- private void completeDbAttributes(Map<String, Object> attributes) {
- try (DbSession dbSession = dbClient.openSession(false);
- Connection connection = dbSession.getConnection()) {
- DatabaseMetaData metadata = connection.getMetaData();
- attributes.put("Database", metadata.getDatabaseProductName());
- attributes.put("Database Version", metadata.getDatabaseProductVersion());
- attributes.put("Username", metadata.getUserName());
- attributes.put("URL", metadata.getURL());
- attributes.put("Driver", metadata.getDriverName());
- attributes.put("Driver Version", metadata.getDriverVersion());
- attributes.put("Version Status", getMigrationStatus());
- } catch (SQLException e) {
- throw new IllegalStateException("Fail to get DB metadata", e);
- }
- }
-}
+++ /dev/null
-/*
- * 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;
-
-public interface DatabaseMonitorMBean {
-
- /**
- * Is database schema up-to-date or should it be upgraded ?
- */
- String getMigrationStatus();
-
- /**
- *
- */
- int getPoolActiveConnections();
-
- /**
- * The maximum number of active connections that can be allocated from this pool at the same time, or negative for no limit.
- */
- int getPoolMaxActiveConnections();
-
- int getPoolIdleConnections();
-
- /**
- * The maximum number of connections that can remain idle in the pool, without extra ones being released, or negative for no limit.
- */
- int getPoolMaxIdleConnections();
-
- /**
- * The minimum number of connections that can remain idle in the pool, without extra ones being created, or zero to create none.
- */
- int getPoolMinIdleConnections();
-
- /**
- * The initial number of connections that are created when the pool is started.
- */
- int getPoolInitialSize();
-
- /**
- * The maximum number of milliseconds that the pool will wait
- * (when there are no available connections) for a connection to be returned before throwing an exception, or -1 to wait indefinitely.
- */
- long getPoolMaxWaitMillis();
-
- /**
- * Flag to remove abandoned connections if they exceed the {@link #getPoolRemoveAbandonedTimeoutSeconds()}.
- */
- boolean getPoolRemoveAbandoned();
-
- /**
- * Timeout in seconds before an abandoned connection can be removed.
- */
- int getPoolRemoveAbandonedTimeoutSeconds();
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+import org.apache.commons.dbcp.BasicDataSource;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo.Section;
+import org.sonar.server.platform.db.migration.version.DatabaseVersion;
+
+import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
+
+/**
+ * Information about database and connection pool
+ */
+public class DatabaseSection extends BaseSectionMBean implements DatabaseSectionMBean {
+
+ private final DatabaseVersion dbVersion;
+ private final DbClient dbClient;
+
+ public DatabaseSection(DatabaseVersion dbVersion, DbClient dbClient) {
+ this.dbVersion = dbVersion;
+ this.dbClient = dbClient;
+ }
+
+ @Override
+ public String name() {
+ return "Database";
+ }
+
+ @Override
+ public String getMigrationStatus() {
+ return dbVersion.getStatus().name();
+ }
+
+ @Override
+ public int getPoolActiveConnections() {
+ return commonsDbcp().getNumActive();
+ }
+
+ @Override
+ public int getPoolMaxActiveConnections() {
+ return commonsDbcp().getMaxActive();
+ }
+
+ @Override
+ public int getPoolIdleConnections() {
+ return commonsDbcp().getNumIdle();
+ }
+
+ @Override
+ public int getPoolMaxIdleConnections() {
+ return commonsDbcp().getMaxIdle();
+ }
+
+ @Override
+ public int getPoolMinIdleConnections() {
+ return commonsDbcp().getMinIdle();
+ }
+
+ @Override
+ public int getPoolInitialSize() {
+ return commonsDbcp().getInitialSize();
+ }
+
+ @Override
+ public long getPoolMaxWaitMillis() {
+ return commonsDbcp().getMaxWait();
+ }
+
+ @Override
+ public boolean getPoolRemoveAbandoned() {
+ return commonsDbcp().getRemoveAbandoned();
+ }
+
+ @Override
+ public int getPoolRemoveAbandonedTimeoutSeconds() {
+ return commonsDbcp().getRemoveAbandonedTimeout();
+ }
+
+ @Override
+ public Section toProtobuf() {
+ Section.Builder protobuf = Section.newBuilder();
+ protobuf.setName(name());
+ completeDbAttributes(protobuf);
+ completePoolAttributes(protobuf);
+ return protobuf.build();
+ }
+
+ private void completePoolAttributes(Section.Builder protobuf) {
+ setAttribute(protobuf, "Pool Active Connections", getPoolActiveConnections());
+ setAttribute(protobuf, "Pool Max Connections", getPoolMaxActiveConnections());
+ setAttribute(protobuf, "Pool Initial Size", getPoolInitialSize());
+ setAttribute(protobuf, "Pool Idle Connections", getPoolIdleConnections());
+ setAttribute(protobuf, "Pool Min Idle Connections", getPoolMinIdleConnections());
+ setAttribute(protobuf, "Pool Max Idle Connections", getPoolMaxIdleConnections());
+ setAttribute(protobuf, "Pool Max Wait (ms)", getPoolMaxWaitMillis());
+ setAttribute(protobuf, "Pool Remove Abandoned", getPoolRemoveAbandoned());
+ setAttribute(protobuf, "Pool Remove Abandoned Timeout (seconds)", getPoolRemoveAbandonedTimeoutSeconds());
+ }
+
+ private BasicDataSource commonsDbcp() {
+ return (BasicDataSource) dbClient.getDatabase().getDataSource();
+ }
+
+ private void completeDbAttributes(Section.Builder protobuf) {
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ DatabaseMetaData metadata = dbSession.getConnection().getMetaData();
+ setAttribute(protobuf, "Database", metadata.getDatabaseProductName());
+ setAttribute(protobuf, "Database Version", metadata.getDatabaseProductVersion());
+ setAttribute(protobuf, "Username", metadata.getUserName());
+ setAttribute(protobuf, "URL", metadata.getURL());
+ setAttribute(protobuf, "Driver", metadata.getDriverName());
+ setAttribute(protobuf, "Driver Version", metadata.getDriverVersion());
+ setAttribute(protobuf, "Version Status", getMigrationStatus());
+ } catch (SQLException e) {
+ throw new IllegalStateException("Fail to get DB metadata", e);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+public interface DatabaseSectionMBean {
+
+ /**
+ * Is database schema up-to-date or should it be upgraded ?
+ */
+ String getMigrationStatus();
+
+ /**
+ *
+ */
+ int getPoolActiveConnections();
+
+ /**
+ * The maximum number of active connections that can be allocated from this pool at the same time, or negative for no limit.
+ */
+ int getPoolMaxActiveConnections();
+
+ int getPoolIdleConnections();
+
+ /**
+ * The maximum number of connections that can remain idle in the pool, without extra ones being released, or negative for no limit.
+ */
+ int getPoolMaxIdleConnections();
+
+ /**
+ * The minimum number of connections that can remain idle in the pool, without extra ones being created, or zero to create none.
+ */
+ int getPoolMinIdleConnections();
+
+ /**
+ * The initial number of connections that are created when the pool is started.
+ */
+ int getPoolInitialSize();
+
+ /**
+ * The maximum number of milliseconds that the pool will wait
+ * (when there are no available connections) for a connection to be returned before throwing an exception, or -1 to wait indefinitely.
+ */
+ long getPoolMaxWaitMillis();
+
+ /**
+ * Flag to remove abandoned connections if they exceed the {@link #getPoolRemoveAbandonedTimeoutSeconds()}.
+ */
+ boolean getPoolRemoveAbandoned();
+
+ /**
+ * Timeout in seconds before an abandoned connection can be removed.
+ */
+ int getPoolRemoveAbandonedTimeoutSeconds();
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-import org.elasticsearch.ElasticsearchException;
-import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
-import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
-import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
-import org.elasticsearch.action.admin.indices.stats.IndexStats;
-import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
-import org.elasticsearch.cluster.health.ClusterHealthStatus;
-import org.elasticsearch.cluster.node.DiscoveryNode;
-import org.elasticsearch.common.breaker.CircuitBreaker;
-import org.sonar.api.utils.log.Loggers;
-import org.sonar.server.es.EsClient;
-
-import static org.apache.commons.io.FileUtils.byteCountToDisplaySize;
-
-public class EsMonitor extends BaseMonitorMBean implements EsMonitorMBean {
-
- private final EsClient esClient;
-
- public EsMonitor(EsClient esClient) {
- this.esClient = esClient;
- }
-
- @Override
- public String name() {
- return "Elasticsearch";
- }
-
- /**
- * MXBean does not allow to return enum {@link ClusterHealthStatus}, so
- * returning String.
- */
- @Override
- public String getState() {
- return getStateAsEnum().name();
- }
-
- private ClusterHealthStatus getStateAsEnum() {
- return clusterStats().getStatus();
- }
-
- @Override
- public int getNumberOfNodes() {
- return clusterStats().getNodesStats().getCounts().getTotal();
- }
-
- @Override
- public Map<String, Object> attributes() {
- try {
- Map<String, Object> attributes = new LinkedHashMap<>();
- attributes.put("State", getStateAsEnum());
- attributes.put("Indices", indexAttributes());
- attributes.put("Number of Nodes", getNumberOfNodes());
- attributes.put("Nodes", nodeAttributes());
- return attributes;
- } catch (Exception es) {
- Loggers.get(EsMonitor.class).warn("Failed to retrieve ES attributes. There will be only a single \"state\" attribute.", es);
- Map<String, Object> attributes = new LinkedHashMap<>();
- attributes.put("State", es.getCause() instanceof ElasticsearchException ? es.getCause().getMessage() : es.getMessage());
- return attributes;
- }
- }
-
- private LinkedHashMap<String, LinkedHashMap<String, Object>> indexAttributes() {
- LinkedHashMap<String, LinkedHashMap<String, Object>> indices = new LinkedHashMap<>();
- IndicesStatsResponse indicesStats = esClient.prepareStats().all().get();
-
- for (Map.Entry<String, IndexStats> indexStats : indicesStats.getIndices().entrySet()) {
- LinkedHashMap<String, Object> attributes = new LinkedHashMap<>();
- indices.put(indexStats.getKey(), attributes);
- attributes.put("Docs", indexStats.getValue().getPrimaries().getDocs().getCount());
- attributes.put("Shards", indexStats.getValue().getShards().length);
- attributes.put("Store Size", byteCountToDisplaySize(indexStats.getValue().getPrimaries().getStore().getSizeInBytes()));
- }
- return indices;
- }
-
- /**
- * map of {node name -> node attributes}
- */
- private LinkedHashMap<String, LinkedHashMap<String, Object>> nodeAttributes() {
- LinkedHashMap<String, LinkedHashMap<String, Object>> nodes = new LinkedHashMap<>();
- NodesStatsResponse nodesStats = esClient.prepareNodesStats().all().get();
- for (Map.Entry<String, NodeStats> entry : nodesStats.getNodesMap().entrySet()) {
-
- LinkedHashMap<String, Object> nodeAttributes = new LinkedHashMap<>();
- NodeStats stats = entry.getValue();
- DiscoveryNode node = stats.getNode();
- nodes.put(node.getName(), nodeAttributes);
- nodeAttributes.put("Address", node.getAddress().toString());
- nodeAttributes.put("Type", node.isMasterNode() ? "Master" : "Slave");
- nodeAttributes.put("Disk Available", byteCountToDisplaySize(stats.getFs().getTotal().getAvailable().getBytes()));
- nodeAttributes.put("Store Size", byteCountToDisplaySize(stats.getIndices().getStore().getSizeInBytes()));
- nodeAttributes.put("Open Files", stats.getProcess().getOpenFileDescriptors());
- nodeAttributes.put("JVM Heap Usage", formatPercent(stats.getJvm().getMem().getHeapUsedPercent()));
- nodeAttributes.put("JVM Heap Used", byteCountToDisplaySize(stats.getJvm().getMem().getHeapUsed().getBytes()));
- nodeAttributes.put("JVM Heap Max", byteCountToDisplaySize(stats.getJvm().getMem().getHeapMax().getBytes()));
- nodeAttributes.put("JVM Non Heap Used", byteCountToDisplaySize(stats.getJvm().getMem().getNonHeapUsed().getBytes()));
- nodeAttributes.put("JVM Threads", stats.getJvm().getThreads().getCount());
- nodeAttributes.put("Field Data Memory", byteCountToDisplaySize(stats.getIndices().getFieldData().getMemorySizeInBytes()));
- nodeAttributes.put("Field Data Circuit Breaker Limit", byteCountToDisplaySize(stats.getBreaker().getStats(CircuitBreaker.FIELDDATA).getLimit()));
- nodeAttributes.put("Field Data Circuit Breaker Estimation", byteCountToDisplaySize(stats.getBreaker().getStats(CircuitBreaker.FIELDDATA).getEstimated()));
- nodeAttributes.put("Request Circuit Breaker Limit", byteCountToDisplaySize(stats.getBreaker().getStats(CircuitBreaker.REQUEST).getLimit()));
- nodeAttributes.put("Request Circuit Breaker Estimation", byteCountToDisplaySize(stats.getBreaker().getStats(CircuitBreaker.REQUEST).getEstimated()));
- nodeAttributes.put("Query Cache Memory", byteCountToDisplaySize(stats.getIndices().getQueryCache().getMemorySizeInBytes()));
- nodeAttributes.put("Request Cache Memory", byteCountToDisplaySize(stats.getIndices().getRequestCache().getMemorySizeInBytes()));
- }
- return nodes;
- }
-
- private ClusterStatsResponse clusterStats() {
- return esClient.prepareClusterStats().get();
- }
-
- private static String formatPercent(long amount) {
- return String.format("%.1f%%", 100 * amount * 1.0D / 100L);
- }
-}
+++ /dev/null
-/*
- * 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;
-
-/**
- * The public attributes of {@link org.sonar.server.platform.monitoring.EsMonitor}
- * to be exported in JMX bean.
- */
-public interface EsMonitorMBean {
- String getState();
- int getNumberOfNodes();
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import java.util.Map;
+import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
+import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
+import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
+import org.elasticsearch.action.admin.indices.stats.IndexStats;
+import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
+import org.elasticsearch.cluster.health.ClusterHealthStatus;
+import org.elasticsearch.common.breaker.CircuitBreaker;
+import org.sonar.api.utils.log.Loggers;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.server.es.EsClient;
+
+import static org.apache.commons.io.FileUtils.byteCountToDisplaySize;
+import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
+
+public class EsSection extends BaseSectionMBean implements EsSectionMBean {
+
+ private final EsClient esClient;
+
+ public EsSection(EsClient esClient) {
+ this.esClient = esClient;
+ }
+
+ @Override
+ public String name() {
+ return "Elasticsearch";
+ }
+
+ /**
+ * MXBean does not allow to return enum {@link ClusterHealthStatus}, so
+ * returning String.
+ */
+ @Override
+ public String getState() {
+ return getStateAsEnum().name();
+ }
+
+ private ClusterHealthStatus getStateAsEnum() {
+ return clusterStats().getStatus();
+ }
+
+ @Override
+ public ProtobufSystemInfo.Section toProtobuf() {
+ ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder();
+ protobuf.setName(name());
+ try {
+ setAttribute(protobuf, "State", getStateAsEnum().name());
+ completeNodeAttributes(protobuf);
+ completeIndexAttributes(protobuf);
+
+ } catch (Exception es) {
+ Loggers.get(EsSection.class).warn("Failed to retrieve ES attributes. There will be only a single \"state\" attribute.", es);
+ setAttribute(protobuf, "State", es.getCause() instanceof ElasticsearchException ? es.getCause().getMessage() : es.getMessage());
+ }
+ return protobuf.build();
+ }
+
+ private void completeIndexAttributes(ProtobufSystemInfo.Section.Builder protobuf) {
+ IndicesStatsResponse indicesStats = esClient.prepareStats().all().get();
+ for (Map.Entry<String, IndexStats> indexStats : indicesStats.getIndices().entrySet()) {
+ String prefix = "Index " + indexStats.getKey() + " - ";
+ setAttribute(protobuf, prefix + "Docs", indexStats.getValue().getPrimaries().getDocs().getCount());
+ setAttribute(protobuf, prefix + "Shards", indexStats.getValue().getShards().length);
+ setAttribute(protobuf, prefix + "Store Size", byteCountToDisplaySize(indexStats.getValue().getPrimaries().getStore().getSizeInBytes()));
+ }
+ }
+
+ private void completeNodeAttributes(ProtobufSystemInfo.Section.Builder protobuf) {
+ NodesStatsResponse nodesStats = esClient.prepareNodesStats().all().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 Files", stats.getProcess().getOpenFileDescriptors());
+ 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();
+ }
+
+ private static String formatPercent(long amount) {
+ return String.format("%.1f%%", 100 * amount * 1.0D / 100L);
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+/**
+ * The public attributes of {@link EsSection}
+ * to be exported in JMX bean.
+ */
+public interface EsSectionMBean {
+ String getState();
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.util.Map;
-import java.util.Objects;
-import java.util.TreeMap;
-
-public class JvmPropsMonitor implements Monitor {
- @Override
- public String name() {
- return "JvmProperties";
- }
-
- @Override
- public Map<String, Object> attributes() {
- Map<String, Object> sortedProps = new TreeMap<>();
- for (Map.Entry<Object, Object> systemProp : System.getProperties().entrySet()) {
- sortedProps.put(Objects.toString(systemProp.getKey()), Objects.toString(systemProp.getValue()));
- }
- return sortedProps;
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.util.Map;
-import org.sonar.api.server.ServerSide;
-import org.sonar.server.platform.ws.InfoAction;
-
-/**
- * Any component that is involved in the information returned by the web service api/system/info
- */
-@ServerSide
-public interface Monitor {
- /**
- * Name of section in System Info page
- */
- String name();
-
- /**
- * Type of attribute values must be supported by {@link org.sonar.api.utils.text.JsonWriter#valueObject(Object)}
- * because of JSON export by {@link InfoAction}.
- */
- Map<String, Object> attributes();
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-import org.sonar.core.platform.PluginInfo;
-import org.sonar.core.platform.PluginRepository;
-import org.sonar.updatecenter.common.Version;
-
-/**
- * Installed plugins (excluding core plugins)
- */
-public class PluginsMonitor implements Monitor {
- private final PluginRepository repository;
-
- public PluginsMonitor(PluginRepository repository) {
- this.repository = repository;
- }
-
- @Override
- public String name() {
- return "Plugins";
- }
-
- @Override
- public Map<String, Object> attributes() {
- Map<String, Object> attributes = new LinkedHashMap<>();
- for (PluginInfo plugin : repository.getPluginInfos()) {
- LinkedHashMap<String, Object> pluginAttributes = new LinkedHashMap<>();
- pluginAttributes.put("Name", plugin.getName());
- Version version = plugin.getVersion();
- if (version != null) {
- pluginAttributes.put("Version", version.getName());
- }
- attributes.put(plugin.getKey(), pluginAttributes);
- }
- return attributes;
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
+import org.sonar.process.systeminfo.SystemInfoSection;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.updatecenter.common.Version;
+
+import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
+
+public class PluginsSection implements SystemInfoSection {
+ private final PluginRepository repository;
+
+ public PluginsSection(PluginRepository repository) {
+ this.repository = repository;
+ }
+
+ @Override
+ public ProtobufSystemInfo.Section toProtobuf() {
+ ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder();
+ protobuf.setName("Plugins");
+ for (PluginInfo plugin : repository.getPluginInfos()) {
+ String label = "[" + plugin.getName() + "]";
+ Version version = plugin.getVersion();
+ if (version != null) {
+ label = version.getName() + " " + label;
+ }
+ setAttribute(protobuf, plugin.getKey(), label);
+ }
+ return protobuf.build();
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import com.google.common.collect.ImmutableSortedMap;
-import java.util.Map;
-import java.util.SortedMap;
-import org.sonar.api.PropertyType;
-import org.sonar.api.config.PropertyDefinition;
-import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.Settings;
-
-import static org.apache.commons.lang.StringUtils.abbreviate;
-
-public class SettingsMonitor implements Monitor {
-
- static final int MAX_VALUE_LENGTH = 500;
- private final Settings settings;
-
- public SettingsMonitor(Settings settings) {
- this.settings = settings;
- }
-
- @Override
- public String name() {
- return "Settings";
- }
-
- @Override
- public SortedMap<String, Object> attributes() {
- PropertyDefinitions definitions = settings.getDefinitions();
- ImmutableSortedMap.Builder<String, Object> builder = ImmutableSortedMap.naturalOrder();
- for (Map.Entry<String, String> prop : settings.getProperties().entrySet()) {
- String key = prop.getKey();
- PropertyDefinition def = definitions.get(key);
- if (def == null || def.type() != PropertyType.PASSWORD) {
- builder.put(key, abbreviate(prop.getValue(), MAX_VALUE_LENGTH));
- }
- }
- return builder.build();
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import java.util.Map;
+import org.sonar.api.PropertyType;
+import org.sonar.api.config.PropertyDefinition;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.Settings;
+import org.sonar.process.systeminfo.SystemInfoSection;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+import static org.apache.commons.lang.StringUtils.abbreviate;
+import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
+
+public class SettingsSection implements SystemInfoSection {
+
+ static final int MAX_VALUE_LENGTH = 500;
+ private final Settings settings;
+
+ public SettingsSection(Settings settings) {
+ this.settings = settings;
+ }
+
+ @Override
+ public ProtobufSystemInfo.Section toProtobuf() {
+ ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder();
+ protobuf.setName("Settings");
+
+ PropertyDefinitions definitions = settings.getDefinitions();
+ for (Map.Entry<String, String> prop : settings.getProperties().entrySet()) {
+ String key = prop.getKey();
+ PropertyDefinition def = definitions.get(key);
+ if (def == null || def.type() != PropertyType.PASSWORD) {
+ setAttribute(protobuf, key, abbreviate(prop.getValue(), MAX_VALUE_LENGTH));
+ }
+ }
+ return protobuf.build();
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import com.google.common.base.Joiner;
-import java.io.File;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import org.sonar.api.CoreProperties;
-import org.sonar.api.config.Configuration;
-import org.sonar.api.platform.Server;
-import org.sonar.api.security.SecurityRealm;
-import org.sonar.api.server.authentication.IdentityProvider;
-import org.sonar.core.util.stream.MoreCollectors;
-import org.sonar.process.ProcessProperties;
-import org.sonar.server.authentication.IdentityProviderRepository;
-import org.sonar.server.platform.ServerIdLoader;
-import org.sonar.server.platform.ServerLogging;
-import org.sonar.server.user.SecurityRealmFactory;
-
-public class SonarQubeMonitor extends BaseMonitorMBean implements SonarQubeMonitorMBean {
-
- private static final Joiner COMMA_JOINER = Joiner.on(", ");
-
- static final String BRANDING_FILE_PATH = "web/WEB-INF/classes/com/sonarsource/branding";
-
- private final Configuration config;
- private final SecurityRealmFactory securityRealmFactory;
- private final IdentityProviderRepository identityProviderRepository;
- private final Server server;
- private final ServerLogging serverLogging;
- private final ServerIdLoader serverIdLoader;
-
- public SonarQubeMonitor(Configuration config, SecurityRealmFactory securityRealmFactory,
- IdentityProviderRepository identityProviderRepository, Server server, ServerLogging serverLogging,
- ServerIdLoader serverIdLoader) {
- this.config = config;
- this.securityRealmFactory = securityRealmFactory;
- this.identityProviderRepository = identityProviderRepository;
- this.server = server;
- this.serverLogging = serverLogging;
- this.serverIdLoader = serverIdLoader;
- }
-
- @Override
- public String getServerId() {
- return serverIdLoader.getRaw().orElse(null);
- }
-
- @Override
- public String getVersion() {
- return server.getVersion();
- }
-
- @Override
- public String getLogLevel() {
- return serverLogging.getRootLoggerLevel().name();
- }
-
- @CheckForNull
- private String getExternalUserAuthentication() {
- SecurityRealm realm = securityRealmFactory.getRealm();
- return realm == null ? null : realm.getName();
- }
-
- private List<String> getEnabledIdentityProviders() {
- return identityProviderRepository.getAllEnabledAndSorted()
- .stream()
- .filter(IdentityProvider::isEnabled)
- .map(IdentityProvider::getName)
- .collect(MoreCollectors.toList());
- }
-
- private List<String> getAllowsToSignUpEnabledIdentityProviders() {
- return identityProviderRepository.getAllEnabledAndSorted()
- .stream()
- .filter(IdentityProvider::isEnabled)
- .filter(IdentityProvider::allowsUsersToSignUp)
- .map(IdentityProvider::getName)
- .collect(MoreCollectors.toList());
- }
-
- private boolean getForceAuthentication() {
- return config.getBoolean(CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY).orElse(false);
- }
-
- private boolean isOfficialDistribution() {
- // the dependency com.sonarsource:sonarsource-branding is shaded to webapp
- // during release (see sonar-web pom)
- File brandingFile = new File(server.getRootDir(), BRANDING_FILE_PATH);
- // no need to check that the file exists. java.io.File#length() returns zero in this case.
- return brandingFile.length() > 0L;
- }
-
- @Override
- public String name() {
- return "SonarQube";
- }
-
- @Override
- public Map<String, Object> attributes() {
- Map<String, Object> attributes = new LinkedHashMap<>();
- completeWithServerIdAttributes(attributes);
- attributes.put("Version", getVersion());
- addIfNotNull("External User Authentication", getExternalUserAuthentication(), attributes);
- addIfNotEmpty("Accepted external identity providers", getEnabledIdentityProviders(), attributes);
- addIfNotEmpty("External identity providers whose users are allowed to sign themselves up", getAllowsToSignUpEnabledIdentityProviders(), attributes);
- attributes.put("Force authentication", getForceAuthentication());
- attributes.put("Official Distribution", isOfficialDistribution());
- attributes.put("Home Dir", config.get(ProcessProperties.PATH_HOME).orElse(null));
- attributes.put("Data Dir", config.get(ProcessProperties.PATH_DATA).orElse(null));
- attributes.put("Temp Dir", config.get(ProcessProperties.PATH_TEMP).orElse(null));
- attributes.put("Logs Dir", config.get(ProcessProperties.PATH_LOGS).orElse(null));
- attributes.put("Logs Level", getLogLevel());
- return attributes;
- }
-
- private void completeWithServerIdAttributes(Map<String, Object> attributes) {
- serverIdLoader.get().ifPresent(serverId -> {
- attributes.put("Server ID", serverId.getId());
- attributes.put("Server ID validated", serverId.isValid());
- });
- }
-
- private static void addIfNotNull(String key, @Nullable String value, Map<String, Object> attributes) {
- if (value != null) {
- attributes.put(key, value);
- }
- }
-
- private static void addIfNotEmpty(String key, List<String> values, Map<String, Object> attributes) {
- if (!values.isEmpty()) {
- attributes.put(key, COMMA_JOINER.join(values));
- }
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import javax.annotation.CheckForNull;
-
-public interface SonarQubeMonitorMBean {
- @CheckForNull
- String getServerId();
-
- String getVersion();
-
- String getLogLevel();
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import com.google.common.base.Joiner;
+import java.io.File;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.platform.Server;
+import org.sonar.api.security.SecurityRealm;
+import org.sonar.api.server.authentication.IdentityProvider;
+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.platform.ServerIdLoader;
+import org.sonar.server.platform.ServerLogging;
+import org.sonar.server.user.SecurityRealmFactory;
+
+import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
+
+public class SonarQubeSection extends BaseSectionMBean implements SonarQubeSectionMBean {
+
+ private static final Joiner COMMA_JOINER = Joiner.on(", ");
+
+ static final String BRANDING_FILE_PATH = "web/WEB-INF/classes/com/sonarsource/branding";
+
+ private final Configuration config;
+ private final SecurityRealmFactory securityRealmFactory;
+ private final IdentityProviderRepository identityProviderRepository;
+ private final Server server;
+ private final ServerLogging serverLogging;
+ private final ServerIdLoader serverIdLoader;
+
+ public SonarQubeSection(Configuration config, SecurityRealmFactory securityRealmFactory,
+ IdentityProviderRepository identityProviderRepository, Server server, ServerLogging serverLogging,
+ ServerIdLoader serverIdLoader) {
+ this.config = config;
+ this.securityRealmFactory = securityRealmFactory;
+ this.identityProviderRepository = identityProviderRepository;
+ this.server = server;
+ this.serverLogging = serverLogging;
+ this.serverIdLoader = serverIdLoader;
+ }
+
+ @Override
+ public String getServerId() {
+ return serverIdLoader.getRaw().orElse(null);
+ }
+
+ @Override
+ public String getVersion() {
+ return server.getVersion();
+ }
+
+ @Override
+ public String getLogLevel() {
+ return serverLogging.getRootLoggerLevel().name();
+ }
+
+ @CheckForNull
+ private String getExternalUserAuthentication() {
+ SecurityRealm realm = securityRealmFactory.getRealm();
+ return realm == null ? null : realm.getName();
+ }
+
+ private List<String> getEnabledIdentityProviders() {
+ return identityProviderRepository.getAllEnabledAndSorted()
+ .stream()
+ .filter(IdentityProvider::isEnabled)
+ .map(IdentityProvider::getName)
+ .collect(MoreCollectors.toList());
+ }
+
+ private List<String> getAllowsToSignUpEnabledIdentityProviders() {
+ return identityProviderRepository.getAllEnabledAndSorted()
+ .stream()
+ .filter(IdentityProvider::isEnabled)
+ .filter(IdentityProvider::allowsUsersToSignUp)
+ .map(IdentityProvider::getName)
+ .collect(MoreCollectors.toList());
+ }
+
+ private boolean getForceAuthentication() {
+ return config.getBoolean(CoreProperties.CORE_FORCE_AUTHENTICATION_PROPERTY).orElse(false);
+ }
+
+ private boolean isOfficialDistribution() {
+ // the dependency com.sonarsource:sonarsource-branding is shaded to webapp
+ // during release (see sonar-web pom)
+ File brandingFile = new File(server.getRootDir(), BRANDING_FILE_PATH);
+ // no need to check that the file exists. java.io.File#length() returns zero in this case.
+ return brandingFile.length() > 0L;
+ }
+
+ @Override
+ public String name() {
+ return "SonarQube";
+ }
+
+ @Override
+ public ProtobufSystemInfo.Section toProtobuf() {
+ ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder();
+ protobuf.setName(name());
+
+ serverIdLoader.get().ifPresent(serverId -> {
+ setAttribute(protobuf, "Server ID", serverId.getId());
+ setAttribute(protobuf, "Server ID validated", serverId.isValid());
+ });
+ setAttribute(protobuf, "Version", getVersion());
+ setAttribute(protobuf, "External User Authentication", getExternalUserAuthentication());
+ addIfNotEmpty(protobuf, "Accepted external identity providers", getEnabledIdentityProviders());
+ addIfNotEmpty(protobuf, "External identity providers whose users are allowed to sign themselves up", getAllowsToSignUpEnabledIdentityProviders());
+ setAttribute(protobuf, "Force authentication", getForceAuthentication());
+ setAttribute(protobuf, "Official Distribution", isOfficialDistribution());
+ setAttribute(protobuf, "Home Dir", config.get(ProcessProperties.PATH_HOME).orElse(null));
+ setAttribute(protobuf, "Data Dir", config.get(ProcessProperties.PATH_DATA).orElse(null));
+ setAttribute(protobuf, "Temp Dir", config.get(ProcessProperties.PATH_TEMP).orElse(null));
+ setAttribute(protobuf, "Logs Dir", config.get(ProcessProperties.PATH_LOGS).orElse(null));
+ setAttribute(protobuf, "Logs Level", getLogLevel());
+ return protobuf.build();
+ }
+
+ private static void addIfNotEmpty(ProtobufSystemInfo.Section.Builder protobuf, String key, @Nullable List<String> values) {
+ if (values != null && !values.isEmpty()) {
+ setAttribute(protobuf, key, COMMA_JOINER.join(values));
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import javax.annotation.CheckForNull;
+
+public interface SonarQubeSectionMBean {
+ @CheckForNull
+ String getServerId();
+
+ String getVersion();
+
+ String getLogLevel();
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.lang.management.ClassLoadingMXBean;
-import java.lang.management.ManagementFactory;
-import java.lang.management.MemoryMXBean;
-import java.lang.management.RuntimeMXBean;
-import java.lang.management.ThreadMXBean;
-import java.util.Date;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import org.sonar.api.utils.System2;
-
-import static org.sonar.api.utils.DateUtils.formatDateTime;
-
-/**
- * JVM runtime information. Not exported as a MXBean because these informations
- * are natively provided.
- */
-public class SystemMonitor implements Monitor {
- private final System2 system;
-
- public SystemMonitor() {
- this(System2.INSTANCE);
- }
-
- SystemMonitor(System2 system) {
- this.system = system;
- }
-
- @Override
- public String name() {
- return "System";
- }
-
- @Override
- public Map<String, Object> attributes() {
- Map<String, Object> attributes = new LinkedHashMap<>();
- attributes.put("System Date", formatDateTime(new Date(system.now())));
- attributes.put("Start Time", formatDateTime(new Date(runtimeMXBean().getStartTime())));
- attributes.put("JVM Vendor", runtimeMXBean().getVmVendor());
- attributes.put("JVM Name", runtimeMXBean().getVmName());
- attributes.put("JVM Version", runtimeMXBean().getVmVersion());
- attributes.put("Processors", runtime().availableProcessors());
- attributes.put("System Classpath", runtimeMXBean().getClassPath());
- attributes.put("BootClassPath", runtimeMXBean().getBootClassPath());
- attributes.put("Library Path", runtimeMXBean().getLibraryPath());
- attributes.put("Total Memory", formatMemory(runtime().totalMemory()));
- attributes.put("Free Memory", formatMemory(runtime().freeMemory()));
- attributes.put("Max Memory", formatMemory(runtime().maxMemory()));
- attributes.put("Heap", memoryMXBean().getHeapMemoryUsage().toString());
- attributes.put("Non Heap", memoryMXBean().getNonHeapMemoryUsage().toString());
- attributes.put("System Load Average", String.format("%.1f%% (last minute)", ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage() * 100.0));
- attributes.put("Loaded Classes", classLoadingMXBean().getLoadedClassCount());
- attributes.put("Total Loaded Classes", classLoadingMXBean().getTotalLoadedClassCount());
- attributes.put("Unloaded Classes", classLoadingMXBean().getUnloadedClassCount());
- attributes.put("Threads", threadMXBean().getThreadCount());
- attributes.put("Threads Peak", threadMXBean().getPeakThreadCount());
- attributes.put("Daemon Thread", threadMXBean().getDaemonThreadCount());
- return attributes;
- }
-
- private static RuntimeMXBean runtimeMXBean() {
- return ManagementFactory.getRuntimeMXBean();
- }
-
- private static Runtime runtime() {
- return Runtime.getRuntime();
- }
-
- private static MemoryMXBean memoryMXBean() {
- return ManagementFactory.getMemoryMXBean();
- }
-
- private static ClassLoadingMXBean classLoadingMXBean() {
- return ManagementFactory.getClassLoadingMXBean();
- }
-
- private static ThreadMXBean threadMXBean() {
- return ManagementFactory.getThreadMXBean();
- }
-
- private static String formatMemory(long memoryInBytes) {
- return String.format("%d MB", memoryInBytes / 1_000_000);
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import java.lang.management.ClassLoadingMXBean;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+import java.lang.management.RuntimeMXBean;
+import java.lang.management.ThreadMXBean;
+import java.util.Date;
+import org.sonar.api.utils.System2;
+import org.sonar.process.systeminfo.SystemInfoSection;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+import static java.lang.String.format;
+import static org.sonar.api.utils.DateUtils.formatDateTime;
+import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
+
+/**
+ * JVM runtime information. Not exported as a MXBean because these information
+ * are natively provided.
+ */
+public class SystemSection implements SystemInfoSection {
+ private final System2 system;
+
+ public SystemSection() {
+ this(System2.INSTANCE);
+ }
+
+ SystemSection(System2 system) {
+ this.system = system;
+ }
+
+ @Override
+ public ProtobufSystemInfo.Section toProtobuf() {
+ ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder();
+ protobuf.setName("System");
+
+ setAttribute(protobuf, "System Date", formatDateTime(new Date(system.now())));
+ setAttribute(protobuf, "Start Time", formatDateTime(new Date(runtimeMXBean().getStartTime())));
+ setAttribute(protobuf, "JVM Vendor", runtimeMXBean().getVmVendor());
+ setAttribute(protobuf, "JVM Name", runtimeMXBean().getVmName());
+ setAttribute(protobuf, "JVM Version", runtimeMXBean().getVmVersion());
+ setAttribute(protobuf, "Processors", runtime().availableProcessors());
+ setAttribute(protobuf, "System Classpath", runtimeMXBean().getClassPath());
+ setAttribute(protobuf, "BootClassPath", runtimeMXBean().getBootClassPath());
+ setAttribute(protobuf, "Library Path", runtimeMXBean().getLibraryPath());
+ setAttribute(protobuf, "Total Memory", formatMemory(runtime().totalMemory()));
+ setAttribute(protobuf, "Free Memory", formatMemory(runtime().freeMemory()));
+ setAttribute(protobuf, "Max Memory", formatMemory(runtime().maxMemory()));
+ setAttribute(protobuf, "Heap", memoryMXBean().getHeapMemoryUsage().toString());
+ setAttribute(protobuf, "Non Heap", memoryMXBean().getNonHeapMemoryUsage().toString());
+ setAttribute(protobuf, "System Load Average", format("%.1f%% (last minute)", ManagementFactory.getOperatingSystemMXBean().getSystemLoadAverage() * 100.0));
+ setAttribute(protobuf, "Loaded Classes", classLoadingMXBean().getLoadedClassCount());
+ setAttribute(protobuf, "Total Loaded Classes", classLoadingMXBean().getTotalLoadedClassCount());
+ setAttribute(protobuf, "Unloaded Classes", classLoadingMXBean().getUnloadedClassCount());
+ setAttribute(protobuf, "Threads", threadMXBean().getThreadCount());
+ setAttribute(protobuf, "Threads Peak", threadMXBean().getPeakThreadCount());
+ setAttribute(protobuf, "Daemon Thread", threadMXBean().getDaemonThreadCount());
+ return protobuf.build();
+ }
+
+ private static RuntimeMXBean runtimeMXBean() {
+ return ManagementFactory.getRuntimeMXBean();
+ }
+
+ private static Runtime runtime() {
+ return Runtime.getRuntime();
+ }
+
+ private static MemoryMXBean memoryMXBean() {
+ return ManagementFactory.getMemoryMXBean();
+ }
+
+ private static ClassLoadingMXBean classLoadingMXBean() {
+ return ManagementFactory.getClassLoadingMXBean();
+ }
+
+ private static ThreadMXBean threadMXBean() {
+ return ManagementFactory.getThreadMXBean();
+ }
+
+ private static String formatMemory(long memoryInBytes) {
+ return format("%d MB", memoryInBytes / 1_000_000);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import org.sonar.process.systeminfo.JvmPropertiesSection;
+import org.sonar.process.systeminfo.JvmStateSection;
+import org.sonar.server.platform.ws.ClusterInfoAction;
+import org.sonar.server.platform.ws.StandaloneInfoAction;
+
+public class WebSystemInfoModule {
+
+ private WebSystemInfoModule() {
+ // do not instantiate
+ }
+
+ public static Object[] forStandaloneMode() {
+ return new Object[] {
+ new JvmPropertiesSection("Web JVM Properties"),
+ new JvmStateSection("Web JVM State"),
+ DatabaseSection.class,
+ EsSection.class,
+ PluginsSection.class,
+ SettingsSection.class,
+ SonarQubeSection.class,
+ SystemSection.class,
+
+ StandaloneInfoAction.class
+ };
+ }
+
+ public static Object[] forClusterMode() {
+ return new Object[] {
+ new JvmPropertiesSection("Web JVM Properties"),
+ new JvmStateSection("Web JVM State"),
+ DatabaseSection.class,
+ EsSection.class,
+ PluginsSection.class,
+
+ ClusterInfoAction.class
+ };
+ }
+}
import org.sonar.server.platform.PersistentSettings;
import org.sonar.server.platform.ServerLogging;
import org.sonar.server.platform.SettingsChangeNotifier;
-import org.sonar.server.platform.monitoring.DatabaseMonitor;
-import org.sonar.server.platform.monitoring.EsMonitor;
-import org.sonar.server.platform.monitoring.JvmPropsMonitor;
-import org.sonar.server.platform.monitoring.PluginsMonitor;
-import org.sonar.server.platform.monitoring.SettingsMonitor;
-import org.sonar.server.platform.monitoring.SonarQubeMonitor;
-import org.sonar.server.platform.monitoring.SystemMonitor;
+import org.sonar.server.platform.monitoring.WebSystemInfoModule;
import org.sonar.server.platform.web.WebPagesFilter;
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.InfoActionModule;
+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;
import org.sonar.server.source.ws.RawAction;
import org.sonar.server.source.ws.ScmAction;
import org.sonar.server.source.ws.SourcesWs;
-import org.sonar.server.telemetry.TelemetryModule;
+import org.sonar.server.telemetry.TelemetryClient;
+import org.sonar.server.telemetry.TelemetryDaemon;
+import org.sonar.server.telemetry.TelemetryDataLoader;
import org.sonar.server.test.index.TestIndex;
import org.sonar.server.test.index.TestIndexDefinition;
import org.sonar.server.test.index.TestIndexer;
// System
ServerLogging.class,
RestartAction.class,
- InfoActionModule.class,
PingAction.class,
UpgradesAction.class,
StatusAction.class,
- SystemMonitor.class,
- SettingsMonitor.class,
- SonarQubeMonitor.class,
- EsMonitor.class,
- PluginsMonitor.class,
- JvmPropsMonitor.class,
- DatabaseMonitor.class,
MigrateDbAction.class,
LogsAction.class,
ChangeLogLevelAction.class,
RecoveryIndexer.class,
ProjectIndexersImpl.class);
- addIfStartupLeader(
- // Telemetry
- TelemetryModule.class);
+
+ // telemetry
+ add(TelemetryDataLoader.class);
+ addIfStartupLeader(TelemetryDaemon.class, TelemetryClient.class);
+
+ // system info
+ add(InfoAction.class);
+ addIfCluster(WebSystemInfoModule.forClusterMode()).otherwiseAdd(WebSystemInfoModule.forStandaloneMode());
addAll(level4AddedComponents);
}
*/
package org.sonar.server.platform.ws;
-import java.util.Map;
+import java.util.Arrays;
import java.util.Optional;
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.process.systeminfo.SystemInfoSection;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
-import org.sonar.server.platform.monitoring.Monitor;
import org.sonar.server.telemetry.TelemetryDataLoader;
import org.sonar.server.user.UserSession;
private final UserSession userSession;
private final CeHttpClient ceHttpClient;
- private final Monitor[] monitors;
+ private final SystemInfoSection[] systemInfoSections;
private final TelemetryDataLoader statistics;
- public InfoAction(UserSession userSession, CeHttpClient ceHttpClient, TelemetryDataLoader statistics, Monitor... monitors) {
+ public InfoAction(UserSession userSession, CeHttpClient ceHttpClient, TelemetryDataLoader statistics, SystemInfoSection... systemInfoSections) {
this.userSession = userSession;
this.ceHttpClient = ceHttpClient;
this.statistics = statistics;
- this.monitors = monitors;
+ this.systemInfoSections = systemInfoSections;
}
@Override
public void handle(Request request, Response response) {
userSession.checkIsSystemAdministrator();
- JsonWriter json = response.newJsonWriter();
- writeJson(json);
- json.close();
+ try (JsonWriter json = response.newJsonWriter()) {
+ writeJson(json);
+ }
}
private void writeJson(JsonWriter json) {
json.beginObject();
- for (Monitor monitor : monitors) {
- Map<String, Object> attributes = monitor.attributes();
- json.name(monitor.name());
- json.beginObject();
- for (Map.Entry<String, Object> attribute : attributes.entrySet()) {
- json.name(attribute.getKey()).valueObject(attribute.getValue());
- }
- json.endObject();
- }
+ Arrays.stream(systemInfoSections)
+ .map(SystemInfoSection::toProtobuf)
+ .forEach(section -> sectionToJson(section, json));
Optional<ProtobufSystemInfo.SystemInfo> ceSysInfo = ceHttpClient.retrieveSystemInfo();
if (ceSysInfo.isPresent()) {
- for (ProtobufSystemInfo.Section section : ceSysInfo.get().getSectionsList()) {
- json.name(section.getName());
- json.beginObject();
- for (ProtobufSystemInfo.Attribute attribute : section.getAttributesList()) {
- writeAttribute(json, attribute);
- }
- json.endObject();
- }
+ ceSysInfo.get().getSectionsList().forEach(section -> sectionToJson(section, json));
}
writeStatistics(json);
json.endObject();
writeTelemetryData(json, statistics.load());
}
- private static void writeAttribute(JsonWriter json, ProtobufSystemInfo.Attribute attribute) {
+ 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 static void attributeToJson(JsonWriter json, ProtobufSystemInfo.Attribute attribute) {
switch (attribute.getValueCase()) {
case BOOLEAN_VALUE:
- json.name(attribute.getKey()).valueObject(attribute.getBooleanValue());
+ json.prop(attribute.getKey(), attribute.getBooleanValue());
break;
case LONG_VALUE:
- json.name(attribute.getKey()).valueObject(attribute.getLongValue());
+ json.prop(attribute.getKey(), attribute.getLongValue());
break;
case DOUBLE_VALUE:
- json.name(attribute.getKey()).valueObject(attribute.getDoubleValue());
+ json.prop(attribute.getKey(), attribute.getDoubleValue());
break;
case STRING_VALUE:
- json.name(attribute.getKey()).valueObject(attribute.getStringValue());
+ json.prop(attribute.getKey(), attribute.getStringValue());
break;
case VALUE_NOT_SET:
break;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.lang.management.ManagementFactory;
-import javax.annotation.CheckForNull;
-import javax.management.InstanceNotFoundException;
-import javax.management.ObjectInstance;
-import javax.management.ObjectName;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class BaseMonitorMBeanTest {
-
- FakeMonitor underTest = new FakeMonitor();
-
- @Test
- public void test_registration() throws Exception {
- assertThat(getMBean()).isNull();
-
- underTest.start();
- assertThat(getMBean()).isNotNull();
-
- underTest.stop();
- assertThat(getMBean()).isNull();
- }
-
- @Test
- public void do_not_fail_when_stopping_unstarted() throws Exception {
- underTest.stop();
- assertThat(getMBean()).isNull();
- }
-
- @CheckForNull
- private ObjectInstance getMBean() throws Exception {
- try {
- return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(underTest.objectName()));
- } catch (InstanceNotFoundException e) {
- return null;
- }
- }
-
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import java.lang.management.ManagementFactory;
+import javax.annotation.CheckForNull;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class BaseSectionMBeanTest {
+
+ private FakeSection underTest = new FakeSection();
+
+ @Test
+ public void test_registration() throws Exception {
+ assertThat(getMBean()).isNull();
+
+ underTest.start();
+ assertThat(getMBean()).isNotNull();
+
+ underTest.stop();
+ assertThat(getMBean()).isNull();
+ }
+
+ @Test
+ public void do_not_fail_when_stopping_unstarted() throws Exception {
+ underTest.stop();
+ assertThat(getMBean()).isNull();
+ }
+
+ @CheckForNull
+ private ObjectInstance getMBean() throws Exception {
+ try {
+ return ManagementFactory.getPlatformMBeanServer().getObjectInstance(new ObjectName(underTest.objectName()));
+ } catch (InstanceNotFoundException e) {
+ return null;
+ }
+ }
+
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.util.Map;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.utils.System2;
-import org.sonar.db.DbTester;
-import org.sonar.server.platform.db.migration.version.DatabaseVersion;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class DatabaseMonitorTest {
-
- @Rule
- public DbTester dbTester = DbTester.create(System2.INSTANCE);
-
- private DatabaseVersion databaseVersion = mock(DatabaseVersion.class);
- private DatabaseMonitor underTest = new DatabaseMonitor(databaseVersion, dbTester.getDbClient());
-
- @Before
- public void setUp() throws Exception {
- when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.UP_TO_DATE);
- }
-
- @Test
- public void name_is_not_empty() {
- assertThat(underTest.name()).isNotEmpty();
- }
-
- @Test
- public void db_info() {
- Map<String, Object> attributes = underTest.attributes();
- assertThat(attributes.get("Database")).isEqualTo("H2");
- assertThat(attributes.get("Database Version").toString()).startsWith("1.");
- assertThat(attributes.get("Username")).isEqualTo("SONAR");
- assertThat(attributes.get("Driver Version").toString()).startsWith("1.");
- }
-
- @Test
- public void pool_info() {
- Map<String, Object> attributes = underTest.attributes();
- assertThat((int) attributes.get("Pool Max Connections")).isGreaterThan(0);
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.db.DbTester;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.server.platform.db.migration.version.DatabaseVersion;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.process.systeminfo.SystemInfoUtils.attribute;
+import static org.sonar.server.platform.monitoring.SystemInfoTesting.assertThatAttributeIs;
+
+public class DatabaseSectionTest {
+
+ @Rule
+ public DbTester dbTester = DbTester.create(System2.INSTANCE);
+
+ private DatabaseVersion databaseVersion = mock(DatabaseVersion.class);
+ private DatabaseSection underTest = new DatabaseSection(databaseVersion, dbTester.getDbClient());
+
+ @Before
+ public void setUp() throws Exception {
+ when(databaseVersion.getStatus()).thenReturn(DatabaseVersion.Status.UP_TO_DATE);
+ }
+
+ @Test
+ public void name_is_not_empty() {
+ assertThat(underTest.name()).isNotEmpty();
+ }
+
+ @Test
+ public void db_info() {
+ ProtobufSystemInfo.Section section = underTest.toProtobuf();
+ assertThatAttributeIs(section, "Database", "H2");
+ assertThat(attribute(section, "Database Version").getStringValue()).startsWith("1.");
+ assertThatAttributeIs(section, "Username", "SONAR");
+ assertThat(attribute(section, "Driver Version").getStringValue()).startsWith("1.");
+ }
+
+ @Test
+ public void pool_info() {
+ ProtobufSystemInfo.Section section = underTest.toProtobuf();
+ assertThat(attribute(section, "Pool Max Connections").getLongValue()).isGreaterThan(0L);
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.util.Map;
-import org.elasticsearch.ElasticsearchException;
-import org.elasticsearch.cluster.health.ClusterHealthStatus;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.server.es.EsClient;
-import org.sonar.server.es.EsTester;
-import org.sonar.server.issue.index.IssueIndexDefinition;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class EsMonitorTest {
-
- @Rule
- public EsTester esTester = new EsTester(new IssueIndexDefinition(new MapSettings().asConfig()));
-
- private EsMonitor underTest = new EsMonitor(esTester.client());
-
- @Test
- public void name() {
- assertThat(underTest.name()).isEqualTo("Elasticsearch");
- }
-
- @Test
- public void cluster_attributes() {
- Map<String, Object> attributes = underTest.attributes();
- assertThat(underTest.getState()).isEqualTo(ClusterHealthStatus.GREEN.name());
- assertThat(attributes.get("State")).isEqualTo(ClusterHealthStatus.GREEN);
- assertThat(attributes.get("Number of Nodes")).isEqualTo(1);
- }
-
- @Test
- public void node_attributes() {
- Map<String, Object> attributes = underTest.attributes();
- Map nodesAttributes = (Map) attributes.get("Nodes");
-
- // one node
- assertThat(nodesAttributes).hasSize(1);
- Map nodeAttributes = (Map) nodesAttributes.values().iterator().next();
- assertThat(nodeAttributes.get("Type")).isEqualTo("Master");
- assertThat(nodeAttributes.get("Store Size")).isNotNull();
- }
-
- @Test
- public void index_attributes() {
- Map<String, Object> attributes = underTest.attributes();
- Map indicesAttributes = (Map) attributes.get("Indices");
-
- // one index "issues"
- Map indexAttributes = (Map) indicesAttributes.get(IssueIndexDefinition.INDEX_TYPE_ISSUE.getIndex());
- assertThat(indexAttributes.get("Docs")).isEqualTo(0L);
- assertThat((int) indexAttributes.get("Shards")).isGreaterThan(0);
- assertThat(indexAttributes.get("Store Size")).isNotNull();
- }
-
- @Test
- public void attributes_displays_exception_message_when_cause_null_when_client_fails() {
- EsClient esClientMock = mock(EsClient.class);
- EsMonitor underTest = new EsMonitor(esClientMock);
- when(esClientMock.prepareClusterStats()).thenThrow(new RuntimeException("RuntimeException with no cause"));
-
- Map<String, Object> attributes = underTest.attributes();
- assertThat(attributes).hasSize(1);
- assertThat(attributes.get("State")).isEqualTo("RuntimeException with no cause");
- }
-
- @Test
- public void attributes_displays_exception_message_when_cause_is_not_ElasticSearchException_when_client_fails() {
- EsClient esClientMock = mock(EsClient.class);
- EsMonitor underTest = new EsMonitor(esClientMock);
- when(esClientMock.prepareClusterStats()).thenThrow(new RuntimeException("RuntimeException with cause not ES", new IllegalArgumentException("some cause message")));
-
- Map<String, Object> attributes = underTest.attributes();
- assertThat(attributes).hasSize(1);
- assertThat(attributes.get("State")).isEqualTo("RuntimeException with cause not ES");
- }
-
- @Test
- public void attributes_displays_cause_message_when_cause_is_ElasticSearchException_when_client_fails() {
- EsClient esClientMock = mock(EsClient.class);
- EsMonitor underTest = new EsMonitor(esClientMock);
- when(esClientMock.prepareClusterStats()).thenThrow(new RuntimeException("RuntimeException with ES cause", new ElasticsearchException("some cause message")));
-
- Map<String, Object> attributes = underTest.attributes();
- assertThat(attributes).hasSize(1);
- assertThat(attributes.get("State")).isEqualTo("some cause message");
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.cluster.health.ClusterHealthStatus;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.server.es.EsClient;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.issue.index.IssueIndexDefinition;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.process.systeminfo.SystemInfoUtils.attribute;
+import static org.sonar.server.platform.monitoring.SystemInfoTesting.assertThatAttributeIs;
+
+public class EsSectionTest {
+
+ @Rule
+ public EsTester esTester = new EsTester(new IssueIndexDefinition(new MapSettings().asConfig()));
+
+ private EsSection underTest = new EsSection(esTester.client());
+
+ @Test
+ public void name() {
+ assertThat(underTest.name()).isEqualTo("Elasticsearch");
+ }
+
+ @Test
+ public void es_state() {
+ assertThat(underTest.getState()).isEqualTo(ClusterHealthStatus.GREEN.name());
+ assertThatAttributeIs(underTest.toProtobuf(), "State", ClusterHealthStatus.GREEN.name());
+ }
+
+ @Test
+ public void node_attributes() {
+ ProtobufSystemInfo.Section section = underTest.toProtobuf();
+ assertThat(attribute(section, "Store Size")).isNotNull();
+ }
+
+ @Test
+ public void index_attributes() {
+ ProtobufSystemInfo.Section section = underTest.toProtobuf();
+
+ // one index "issues"
+ assertThat(attribute(section, "Index issues - Docs").getLongValue()).isEqualTo(0L);
+ assertThat(attribute(section, "Index issues - Shards").getLongValue()).isGreaterThan(0);
+ assertThat(attribute(section, "Index issues - Store Size").getStringValue()).isNotNull();
+ }
+
+ @Test
+ public void attributes_displays_exception_message_when_cause_null_when_client_fails() {
+ EsClient esClientMock = mock(EsClient.class);
+ EsSection underTest = new EsSection(esClientMock);
+ when(esClientMock.prepareClusterStats()).thenThrow(new RuntimeException("RuntimeException with no cause"));
+
+ ProtobufSystemInfo.Section section = underTest.toProtobuf();
+ assertThatAttributeIs(section, "State", "RuntimeException with no cause");
+ }
+
+ @Test
+ public void attributes_displays_exception_message_when_cause_is_not_ElasticSearchException_when_client_fails() {
+ EsClient esClientMock = mock(EsClient.class);
+ EsSection underTest = new EsSection(esClientMock);
+ when(esClientMock.prepareClusterStats()).thenThrow(new RuntimeException("RuntimeException with cause not ES", new IllegalArgumentException("some cause message")));
+
+ ProtobufSystemInfo.Section section = underTest.toProtobuf();
+ assertThatAttributeIs(section, "State", "RuntimeException with cause not ES");
+ }
+
+ @Test
+ public void attributes_displays_cause_message_when_cause_is_ElasticSearchException_when_client_fails() {
+ EsClient esClientMock = mock(EsClient.class);
+ EsSection underTest = new EsSection(esClientMock);
+ when(esClientMock.prepareClusterStats()).thenThrow(new RuntimeException("RuntimeException with ES cause", new ElasticsearchException("some cause message")));
+
+ ProtobufSystemInfo.Section section = underTest.toProtobuf();
+ assertThatAttributeIs(section, "State", "some cause message");
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.util.Collections;
-import java.util.Map;
-
-public class FakeMonitor extends BaseMonitorMBean implements FakeMonitorMBean {
-
- @Override
- public int getFake() {
- return 42;
- }
-
- @Override
- public String name() {
- return "fake";
- }
-
- @Override
- public Map<String, Object> attributes() {
- return Collections.emptyMap();
- }
-}
+++ /dev/null
-/*
- * 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;
-
-public interface FakeMonitorMBean {
- int getFake();
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+public class FakeSection extends BaseSectionMBean implements FakeSectionMBean {
+
+ @Override
+ public int getFake() {
+ return 42;
+ }
+
+ @Override
+ public String name() {
+ return "fake";
+ }
+
+ @Override
+ public ProtobufSystemInfo.Section toProtobuf() {
+ return ProtobufSystemInfo.Section.newBuilder().build();
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+public interface FakeSectionMBean {
+ int getFake();
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.util.Map;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class JvmPropsMonitorTest {
-
- JvmPropsMonitor underTest = new JvmPropsMonitor();
-
- @Test
- public void name_is_not_empty() {
- assertThat(underTest.name()).isNotEmpty();
- }
-
- @Test
- public void attributes() {
- Map<String, Object> attributes = underTest.attributes();
-
- assertThat(attributes).containsKeys("java.vm.vendor", "os.name");
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.util.Arrays;
-import java.util.Map;
-import org.junit.Test;
-import org.sonar.core.platform.PluginInfo;
-import org.sonar.core.platform.PluginRepository;
-import org.sonar.updatecenter.common.Version;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class PluginsMonitorTest {
-
- PluginRepository repo = mock(PluginRepository.class);
- PluginsMonitor underTest = new PluginsMonitor(repo);
-
- @Test
- public void name() {
- assertThat(underTest.name()).isEqualTo("Plugins");
- }
-
- @Test
- public void plugin_name_and_version() {
- when(repo.getPluginInfos()).thenReturn(Arrays.asList(
- new PluginInfo("key-1")
- .setName("plugin-1")
- .setVersion(Version.create("1.1")),
- new PluginInfo("key-2")
- .setName("plugin-2")
- .setVersion(Version.create("2.2")),
- new PluginInfo("no-version")
- .setName("No Version")));
-
- Map<String, Object> attributes = underTest.attributes();
-
- assertThat(attributes).containsKeys("key-1", "key-2");
- assertThat((Map) attributes.get("key-1"))
- .containsEntry("Name", "plugin-1")
- .containsEntry("Version", "1.1");
- assertThat((Map) attributes.get("key-2"))
- .containsEntry("Name", "plugin-2")
- .containsEntry("Version", "2.2");
- assertThat((Map) attributes.get("no-version"))
- .containsEntry("Name", "No Version")
- .doesNotContainKey("Version");
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import java.util.Arrays;
+import org.junit.Test;
+import org.sonar.core.platform.PluginInfo;
+import org.sonar.core.platform.PluginRepository;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.updatecenter.common.Version;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.server.platform.monitoring.SystemInfoTesting.assertThatAttributeIs;
+
+public class PluginsSectionTest {
+
+ private PluginRepository repo = mock(PluginRepository.class);
+ private PluginsSection underTest = new PluginsSection(repo);
+
+ @Test
+ public void name() {
+ assertThat(underTest.toProtobuf().getName()).isEqualTo("Plugins");
+ }
+
+ @Test
+ public void plugin_name_and_version() {
+ when(repo.getPluginInfos()).thenReturn(Arrays.asList(
+ new PluginInfo("key-1")
+ .setName("Plugin 1")
+ .setVersion(Version.create("1.1")),
+ new PluginInfo("key-2")
+ .setName("Plugin 2")
+ .setVersion(Version.create("2.2")),
+ new PluginInfo("no-version")
+ .setName("No Version")));
+
+ ProtobufSystemInfo.Section section = underTest.toProtobuf();
+
+ assertThatAttributeIs(section, "key-1", "1.1 [Plugin 1]");
+ assertThatAttributeIs(section, "key-2", "2.2 [Plugin 2]");
+ assertThatAttributeIs(section, "no-version", "[No Version]");
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.util.SortedMap;
-import org.junit.Test;
-import org.sonar.api.PropertyType;
-import org.sonar.api.config.PropertyDefinition;
-import org.sonar.api.config.PropertyDefinitions;
-import org.sonar.api.config.Settings;
-import org.sonar.api.config.internal.MapSettings;
-
-import static org.apache.commons.lang.StringUtils.repeat;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.entry;
-
-public class SettingsMonitorTest {
-
- private static final String PASSWORD_PROPERTY = "sonar.password";
-
- PropertyDefinitions defs = new PropertyDefinitions(PropertyDefinition.builder(PASSWORD_PROPERTY).type(PropertyType.PASSWORD).build());
- Settings settings = new MapSettings(defs);
- SettingsMonitor underTest = new SettingsMonitor(settings);
-
- @Test
- public void return_properties_and_sort_by_key() {
- settings.setProperty("foo", "foo value");
- settings.setProperty("bar", "bar value");
-
- SortedMap<String, Object> attributes = underTest.attributes();
- assertThat(attributes).containsExactly(entry("bar", "bar value"), entry("foo", "foo value"));
- }
-
- @Test
- public void truncate_long_property_values() {
- settings.setProperty("foo", repeat("abcde", 1_000));
-
- String value = (String) underTest.attributes().get("foo");
- assertThat(value).hasSize(SettingsMonitor.MAX_VALUE_LENGTH).startsWith("abcde");
- }
-
- @Test
- public void exclude_password_properties() {
- settings.setProperty(PASSWORD_PROPERTY, "abcde");
-
- assertThat(underTest.attributes()).isEmpty();
- }
-
- @Test
- public void test_monitor_name() {
- assertThat(underTest.name()).isEqualTo("Settings");
-
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import org.junit.Test;
+import org.sonar.api.PropertyType;
+import org.sonar.api.config.PropertyDefinition;
+import org.sonar.api.config.PropertyDefinitions;
+import org.sonar.api.config.Settings;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+import static org.apache.commons.lang.StringUtils.repeat;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.process.systeminfo.SystemInfoUtils.attribute;
+import static org.sonar.server.platform.monitoring.SystemInfoTesting.assertThatAttributeIs;
+
+public class SettingsSectionTest {
+
+ private static final String PASSWORD_PROPERTY = "sonar.password";
+
+ private PropertyDefinitions defs = new PropertyDefinitions(PropertyDefinition.builder(PASSWORD_PROPERTY).type(PropertyType.PASSWORD).build());
+ private Settings settings = new MapSettings(defs);
+ private SettingsSection underTest = new SettingsSection(settings);
+
+ @Test
+ public void return_properties_and_sort_by_key() {
+ settings.setProperty("foo", "foo value");
+ settings.setProperty("bar", "bar value");
+
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThatAttributeIs(protobuf, "bar", "bar value");
+ assertThatAttributeIs(protobuf, "foo", "foo value");
+ }
+
+ @Test
+ public void truncate_long_property_values() {
+ settings.setProperty("foo", repeat("abcde", 1_000));
+
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ String value = attribute(protobuf, "foo").getStringValue();
+ assertThat(value).hasSize(SettingsSection.MAX_VALUE_LENGTH).startsWith("abcde");
+ }
+
+ @Test
+ public void exclude_password_properties() {
+ settings.setProperty(PASSWORD_PROPERTY, "abcde");
+
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThat(attribute(protobuf, PASSWORD_PROPERTY)).isNull();
+ }
+
+ @Test
+ public void test_monitor_name() {
+ assertThat(underTest.toProtobuf().getName()).isEqualTo("Settings");
+
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.io.File;
-import java.util.Map;
-import java.util.Optional;
-import org.apache.commons.io.FileUtils;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.api.platform.Server;
-import org.sonar.api.security.SecurityRealm;
-import org.sonar.api.utils.log.LoggerLevel;
-import org.sonar.server.authentication.IdentityProviderRepositoryRule;
-import org.sonar.server.authentication.TestIdentityProvider;
-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 org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.data.MapEntry.entry;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class SonarQubeMonitorTest {
-
- private static final String SERVER_ID_PROPERTY = "Server ID";
- private static final String SERVER_ID_VALIDATED_PROPERTY = "Server ID validated";
-
- @Rule
- public TemporaryFolder temp = new TemporaryFolder();
-
- @Rule
- public IdentityProviderRepositoryRule identityProviderRepository = new IdentityProviderRepositoryRule();
-
- MapSettings settings = new MapSettings();
- Server server = mock(Server.class);
- ServerIdLoader serverIdLoader = mock(ServerIdLoader.class);
- ServerLogging serverLogging = mock(ServerLogging.class);
- SecurityRealmFactory securityRealmFactory = mock(SecurityRealmFactory.class);
-
- SonarQubeMonitor underTest = new SonarQubeMonitor(settings.asConfig(), securityRealmFactory, identityProviderRepository, server,
- serverLogging, serverIdLoader);
-
- @Before
- public void setUp() throws Exception {
- when(serverLogging.getRootLoggerLevel()).thenReturn(LoggerLevel.DEBUG);
- when(serverIdLoader.getRaw()).thenReturn(Optional.empty());
- when(serverIdLoader.get()).thenReturn(Optional.empty());
- }
-
- @Test
- public void name_is_not_empty() {
- assertThat(underTest.name()).isNotEmpty();
- }
-
- @Test
- public void test_getServerId() {
- when(serverIdLoader.getRaw()).thenReturn(Optional.of("ABC"));
- assertThat(underTest.getServerId()).isEqualTo("ABC");
-
- when(serverIdLoader.getRaw()).thenReturn(Optional.<String>empty());
- assertThat(underTest.getServerId()).isNull();
- }
-
- @Test
- public void attributes_contain_information_about_valid_server_id() {
- when(serverIdLoader.get()).thenReturn(Optional.of(new ServerId("ABC", true)));
-
- Map<String, Object> attributes = underTest.attributes();
- assertThat(attributes).contains(entry(SERVER_ID_PROPERTY, "ABC"), entry(SERVER_ID_VALIDATED_PROPERTY, true));
- }
-
- @Test
- public void attributes_contain_information_about_non_valid_server_id() {
- when(serverIdLoader.get()).thenReturn(Optional.of(new ServerId("ABC", false)));
-
- Map<String, Object> attributes = underTest.attributes();
- assertThat(attributes).contains(entry(SERVER_ID_PROPERTY, "ABC"), entry(SERVER_ID_VALIDATED_PROPERTY, false));
- }
-
- @Test
- public void attributes_do_not_contain_information_about_server_id_if_absent() {
- when(serverIdLoader.get()).thenReturn(Optional.<ServerId>empty());
-
- Map<String, Object> attributes = underTest.attributes();
- assertThat(attributes).doesNotContainKeys(SERVER_ID_PROPERTY, SERVER_ID_VALIDATED_PROPERTY);
- }
-
- @Test
- public void official_distribution() throws Exception {
- File rootDir = temp.newFolder();
- FileUtils.write(new File(rootDir, SonarQubeMonitor.BRANDING_FILE_PATH), "1.2");
-
- when(server.getRootDir()).thenReturn(rootDir);
-
- Map<String, Object> attributes = underTest.attributes();
- assertThat(attributes).containsEntry("Official Distribution", Boolean.TRUE);
- }
-
- @Test
- public void not_an_official_distribution() throws Exception {
- File rootDir = temp.newFolder();
- // branding file is missing
- when(server.getRootDir()).thenReturn(rootDir);
-
- Map<String, Object> attributes = underTest.attributes();
- assertThat(attributes).containsEntry("Official Distribution", Boolean.FALSE);
- }
-
- @Test
- public void get_log_level() throws Exception {
- Map<String, Object> attributes = underTest.attributes();
- assertThat(attributes).containsEntry("Logs Level", "DEBUG");
- }
-
- @Test
- public void get_realm() throws Exception {
- SecurityRealm realm = mock(SecurityRealm.class);
- when(realm.getName()).thenReturn("LDAP");
- when(securityRealmFactory.getRealm()).thenReturn(realm);
-
- Map<String, Object> attributes = underTest.attributes();
- assertThat(attributes).containsEntry("External User Authentication", "LDAP");
- }
-
- @Test
- public void no_realm() throws Exception {
- when(securityRealmFactory.getRealm()).thenReturn(null);
-
- Map<String, Object> attributes = underTest.attributes();
- assertThat(attributes).doesNotContainKey("External User Authentication");
- }
-
- @Test
- public void get_enabled_identity_providers() throws Exception {
- identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
- .setKey("github")
- .setName("GitHub")
- .setEnabled(true));
- identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
- .setKey("bitbucket")
- .setName("Bitbucket")
- .setEnabled(true));
- identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
- .setKey("disabled")
- .setName("Disabled")
- .setEnabled(false));
-
- Map<String, Object> attributes = underTest.attributes();
- assertThat(attributes).containsEntry("Accepted external identity providers", "Bitbucket, GitHub");
- }
-
- @Test
- public void get_enabled_identity_providers_allowing_users_to_signup() throws Exception {
- identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
- .setKey("github")
- .setName("GitHub")
- .setEnabled(true)
- .setAllowsUsersToSignUp(true));
- identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
- .setKey("bitbucket")
- .setName("Bitbucket")
- .setEnabled(true)
- .setAllowsUsersToSignUp(false));
- identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
- .setKey("disabled")
- .setName("Disabled")
- .setEnabled(false)
- .setAllowsUsersToSignUp(true));
-
- Map<String, Object> attributes = underTest.attributes();
- assertThat(attributes).containsEntry("External identity providers whose users are allowed to sign themselves up", "GitHub");
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import java.io.File;
+import java.util.Optional;
+import org.apache.commons.io.FileUtils;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.api.platform.Server;
+import org.sonar.api.security.SecurityRealm;
+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.platform.ServerId;
+import org.sonar.server.platform.ServerIdLoader;
+import org.sonar.server.platform.ServerLogging;
+import org.sonar.server.user.SecurityRealmFactory;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.process.systeminfo.SystemInfoUtils.attribute;
+import static org.sonar.server.platform.monitoring.SystemInfoTesting.assertThatAttributeIs;
+
+public class SonarQubeSectionTest {
+
+ private static final String SERVER_ID_PROPERTY = "Server ID";
+ private static final String SERVER_ID_VALIDATED_PROPERTY = "Server ID validated";
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ @Rule
+ public IdentityProviderRepositoryRule identityProviderRepository = new IdentityProviderRepositoryRule();
+
+ private MapSettings settings = new MapSettings();
+ private Server server = mock(Server.class);
+ private ServerIdLoader serverIdLoader = mock(ServerIdLoader.class);
+ private ServerLogging serverLogging = mock(ServerLogging.class);
+ private SecurityRealmFactory securityRealmFactory = mock(SecurityRealmFactory.class);
+
+ private SonarQubeSection underTest = new SonarQubeSection(settings.asConfig(), securityRealmFactory, identityProviderRepository, server,
+ serverLogging, serverIdLoader);
+
+ @Before
+ public void setUp() throws Exception {
+ when(serverLogging.getRootLoggerLevel()).thenReturn(LoggerLevel.DEBUG);
+ when(serverIdLoader.getRaw()).thenReturn(Optional.empty());
+ when(serverIdLoader.get()).thenReturn(Optional.empty());
+ }
+
+ @Test
+ public void name_is_not_empty() {
+ assertThat(underTest.name()).isNotEmpty();
+ }
+
+ @Test
+ public void test_getServerId() {
+ when(serverIdLoader.getRaw()).thenReturn(Optional.of("ABC"));
+ assertThat(underTest.getServerId()).isEqualTo("ABC");
+
+ when(serverIdLoader.getRaw()).thenReturn(Optional.empty());
+ assertThat(underTest.getServerId()).isNull();
+ }
+
+ @Test
+ public void attributes_contain_information_about_valid_server_id() {
+ when(serverIdLoader.get()).thenReturn(Optional.of(new ServerId("ABC", true)));
+
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThatAttributeIs(protobuf, SERVER_ID_PROPERTY, "ABC");
+ assertThatAttributeIs(protobuf, SERVER_ID_VALIDATED_PROPERTY, true);
+ }
+
+ @Test
+ public void attributes_contain_information_about_non_valid_server_id() {
+ when(serverIdLoader.get()).thenReturn(Optional.of(new ServerId("ABC", false)));
+
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThatAttributeIs(protobuf, SERVER_ID_PROPERTY, "ABC");
+ assertThatAttributeIs(protobuf, SERVER_ID_VALIDATED_PROPERTY, false);
+ }
+
+ @Test
+ public void attributes_do_not_contain_information_about_server_id_if_absent() {
+ when(serverIdLoader.get()).thenReturn(Optional.empty());
+
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThat(attribute(protobuf, SERVER_ID_PROPERTY)).isNull();
+ assertThat(attribute(protobuf, SERVER_ID_VALIDATED_PROPERTY)).isNull();
+ }
+
+ @Test
+ public void official_distribution() throws Exception {
+ File rootDir = temp.newFolder();
+ FileUtils.write(new File(rootDir, SonarQubeSection.BRANDING_FILE_PATH), "1.2");
+
+ when(server.getRootDir()).thenReturn(rootDir);
+
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThatAttributeIs(protobuf, "Official Distribution", true);
+ }
+
+ @Test
+ public void not_an_official_distribution() throws Exception {
+ File rootDir = temp.newFolder();
+ // branding file is missing
+ when(server.getRootDir()).thenReturn(rootDir);
+
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThatAttributeIs(protobuf, "Official Distribution", false);
+ }
+
+ @Test
+ public void get_log_level() throws Exception {
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThatAttributeIs(protobuf, "Logs Level", "DEBUG");
+ }
+
+ @Test
+ public void get_realm() throws Exception {
+ SecurityRealm realm = mock(SecurityRealm.class);
+ when(realm.getName()).thenReturn("LDAP");
+ when(securityRealmFactory.getRealm()).thenReturn(realm);
+
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThatAttributeIs(protobuf, "External User Authentication", "LDAP");
+ }
+
+ @Test
+ public void no_realm() throws Exception {
+ when(securityRealmFactory.getRealm()).thenReturn(null);
+
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThat(attribute(protobuf, "External User Authentication")).isNull();
+ }
+
+ @Test
+ public void get_enabled_identity_providers() throws Exception {
+ identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
+ .setKey("github")
+ .setName("GitHub")
+ .setEnabled(true));
+ identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
+ .setKey("bitbucket")
+ .setName("Bitbucket")
+ .setEnabled(true));
+ identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
+ .setKey("disabled")
+ .setName("Disabled")
+ .setEnabled(false));
+
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThatAttributeIs(protobuf, "Accepted external identity providers", "Bitbucket, GitHub");
+ }
+
+ @Test
+ public void get_enabled_identity_providers_allowing_users_to_signup() throws Exception {
+ identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
+ .setKey("github")
+ .setName("GitHub")
+ .setEnabled(true)
+ .setAllowsUsersToSignUp(true));
+ identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
+ .setKey("bitbucket")
+ .setName("Bitbucket")
+ .setEnabled(true)
+ .setAllowsUsersToSignUp(false));
+ identityProviderRepository.addIdentityProvider(new TestIdentityProvider()
+ .setKey("disabled")
+ .setName("Disabled")
+ .setEnabled(false)
+ .setAllowsUsersToSignUp(true));
+
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThatAttributeIs(protobuf, "External identity providers whose users are allowed to sign themselves up", "GitHub");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+import static org.sonar.process.systeminfo.SystemInfoUtils.attribute;
+
+public class SystemInfoTesting {
+
+ private SystemInfoTesting() {
+ // do not instantiate
+ }
+
+ public static void assertThatAttributeIs(ProtobufSystemInfo.Section section, String key, String expectedValue) {
+ ProtobufSystemInfo.Attribute value = attribute(section, key);
+ assertThat(value).as(key).isNotNull();
+ assertThat(value.getStringValue()).isEqualTo(expectedValue);
+ }
+
+ public static void assertThatAttributeIs(ProtobufSystemInfo.Section section, String key, boolean expectedValue) {
+ ProtobufSystemInfo.Attribute value = attribute(section, key);
+ assertThat(value).as(key).isNotNull();
+ assertThat(value.getBooleanValue()).isEqualTo(expectedValue);
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.sonar.server.platform.monitoring;
-
-import java.util.Map;
-import org.junit.Test;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class SystemMonitorTest {
-
- SystemMonitor underTest = new SystemMonitor();
-
- @Test
- public void name() {
- assertThat(underTest.name()).isEqualTo("System");
- }
-
- @Test
- public void system_properties() {
- Map<String, Object> attributes = underTest.attributes();
-
- assertThat(attributes).containsKeys("System Date", "Processors");
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import org.junit.Test;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.sonar.process.systeminfo.SystemInfoUtils.attribute;
+
+public class SystemSectionTest {
+
+ private SystemSection underTest = new SystemSection();
+
+ @Test
+ public void name() {
+ assertThat(underTest.toProtobuf().getName()).isEqualTo("System");
+ }
+
+ @Test
+ public void system_properties() {
+ ProtobufSystemInfo.Section section = underTest.toProtobuf();
+
+ assertThat(attribute(section, "System Date").getStringValue()).isNotEmpty();
+ assertThat(attribute(section, "Processors").getLongValue()).isGreaterThan(0);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.platform.monitoring;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class WebSystemInfoModuleTest {
+
+ @Test
+ public void test_forStandaloneMode() {
+ assertThat(WebSystemInfoModule.forStandaloneMode())
+ .isNotEmpty()
+ .doesNotContainNull();
+ }
+
+ @Test
+ public void test_forClusterMode() {
+ assertThat(WebSystemInfoModule.forClusterMode())
+ .isNotEmpty()
+ .doesNotContainNull();
+ }
+}
+++ /dev/null
-/*
- * 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.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
-
-public class InfoActionModuleTest {
- @Test
- public void verify_count_of_added_components() {
- ComponentContainer container = new ComponentContainer();
-
- new InfoActionModule().configure(container);
-
- assertThat(container.size()).isEqualTo(4 + COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER);
- }
-
-}
*/
package org.sonar.server.platform.ws;
-import java.util.LinkedHashMap;
-import java.util.Map;
import java.util.Optional;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mockito;
import org.sonar.ce.http.CeHttpClient;
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.platform.monitoring.Monitor;
import org.sonar.server.telemetry.TelemetryData;
import org.sonar.server.telemetry.TelemetryDataLoader;
import org.sonar.server.tester.UserSessionRule;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
public class InfoActionTest {
@Rule
@Rule
public ExpectedException expectedException = ExpectedException.none();
- private Monitor monitor1 = mock(Monitor.class);
- private Monitor monitor2 = mock(Monitor.class);
+ private SystemInfoSection section1 = mock(SystemInfoSection.class);
+ private SystemInfoSection section2 = mock(SystemInfoSection.class);
private CeHttpClient ceHttpClient = mock(CeHttpClientImpl.class, Mockito.RETURNS_MOCKS);
private TelemetryDataLoader statistics = mock(TelemetryDataLoader.class);
- private InfoAction underTest = new InfoAction(userSessionRule, ceHttpClient, statistics, monitor1, monitor2);
+ private InfoAction underTest = new InfoAction(userSessionRule, ceHttpClient, statistics, section1, section2);
private WsActionTester ws = new WsActionTester(underTest);
@Test
public void write_json() {
logInAsSystemAdministrator();
- Map<String, Object> attributes1 = new LinkedHashMap<>();
- attributes1.put("foo", "bar");
- Map<String, Object> attributes2 = new LinkedHashMap<>();
- attributes2.put("one", 1);
- attributes2.put("two", 2);
- when(monitor1.name()).thenReturn("Monitor One");
- when(monitor1.attributes()).thenReturn(attributes1);
- when(monitor2.name()).thenReturn("Monitor Two");
- when(monitor2.attributes()).thenReturn(attributes2);
+ ProtobufSystemInfo.Section.Builder attributes1 = ProtobufSystemInfo.Section.newBuilder()
+ .setName("Section One");
+ setAttribute(attributes1, "foo", "bar");
+ when(section1.toProtobuf()).thenReturn(attributes1.build());
+
+ ProtobufSystemInfo.Section.Builder attributes2 = ProtobufSystemInfo.Section.newBuilder()
+ .setName("Section Two");
+ setAttribute(attributes2, "one", 1);
+ setAttribute(attributes2, "two", 2);
+ when(section2.toProtobuf()).thenReturn(attributes2.build());
when(ceHttpClient.retrieveSystemInfo()).thenReturn(Optional.empty());
when(statistics.load()).thenReturn(mock(TelemetryData.class));
TestResponse response = ws.newRequest().execute();
- // response does not contain empty "Monitor Three"
+ // response does not contain empty "Section Three"
verify(statistics).load();
- assertThat(response.getInput()).isEqualTo("{\"Monitor One\":{\"foo\":\"bar\"},\"Monitor Two\":{\"one\":1,\"two\":2}," +
+ assertThat(response.getInput()).isEqualTo("{\"Section One\":{\"foo\":\"bar\"},\"Section Two\":{\"one\":1,\"two\":2}," +
"\"Statistics\":{\"plugins\":{},\"userCount\":0,\"projectCount\":0,\"lines\":0,\"ncloc\":0,\"projectCountByLanguage\":{},\"nclocByLanguage\":{}}}");
}
+++ /dev/null
-/*
- * 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.telemetry;
-
-import org.junit.Test;
-import org.sonar.core.platform.ComponentContainer;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.core.platform.ComponentContainer.COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER;
-
-public class TelemetryModuleTest {
- @Test
- public void verify_count_of_added_components() {
- ComponentContainer container = new ComponentContainer();
-
- new TelemetryModule().configure(container);
-
- assertThat(container.size()).isEqualTo(2 + COMPONENTS_IN_EMPTY_COMPONENT_CONTAINER);
- }
-}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { getJSON, post } from '../helpers/request';
+import throwGlobalError from '../app/utils/throwGlobalError';
-export function setLogLevel(level: string): Promise<void> {
- return post('/api/system/change_log_level', { level });
+export type SysValue = boolean | string | number | HealthType | SysValueObject | SysValueArray;
+export interface SysValueObject {
+ [key: string]: SysValue;
}
+export interface SysValueArray extends Array<SysValue> {}
-export function getSystemInfo(): Promise<any> {
- return getJSON('/api/system/info');
+export interface SysInfoSection {
+ [sectionName: string]: SysValueObject;
+}
+
+export enum HealthType {
+ RED = 'RED',
+ YELLOW = 'YELLOW',
+ GREEN = 'GREEN'
+}
+
+export interface HealthCause extends SysValueObject {
+ message: string;
+}
+
+export interface NodeInfo extends SysValueObject {
+ Name: string;
+ Health: HealthType;
+ 'Health Causes': HealthCause[];
+}
+
+export interface SysInfo extends SysValueObject {
+ Cluster: boolean;
+ Health: HealthType;
+ 'Health Causes': HealthCause[];
+ 'Application Nodes': NodeInfo[];
+ 'Search Nodes': NodeInfo[];
+}
+
+export function setLogLevel(level: string): Promise<void | Response> {
+ return post('/api/system/change_log_level', { level }).catch(throwGlobalError);
+}
+
+export function getSystemInfo(): Promise<SysInfo> {
+ return getJSON('/api/system/info').catch(throwGlobalError);
}
export function getSystemStatus(): Promise<any> {
return getJSON('/api/system/status');
}
-export function restart(): Promise<void> {
- return post('/api/system/restart');
+export function restart(): Promise<void | Response> {
+ return post('/api/system/restart').catch(throwGlobalError);
}
const POLLING_INTERVAL = 2000;
--- /dev/null
+/*
+ * 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.
+ */
+import * as utils from '../utils';
+
+describe('parseQuery', () => {
+ it('should correctly parse the expand array', () => {
+ expect(utils.parseQuery({})).toEqual({ expandedCards: [] });
+ expect(utils.parseQuery({ expand: 'foo,bar' })).toEqual({ expandedCards: ['foo', 'bar'] });
+ });
+});
+
+describe('serializeQuery', () => {
+ it('should correctly serialize the expand array', () => {
+ expect(utils.serializeQuery({ expandedCards: [] })).toEqual({});
+ expect(utils.serializeQuery({ expandedCards: ['foo', 'bar'] })).toEqual({ expand: 'foo,bar' });
+ });
+});
+
+describe('groupSections', () => {
+ it('should correctly group the root field into a main section', () => {
+ expect(utils.groupSections({ foo: 'Foo', bar: 3, baz: { a: 'a' } })).toEqual({
+ mainSection: { foo: 'Foo', bar: 3 },
+ sections: { baz: { a: 'a' } }
+ });
+ });
+});
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import * as PropTypes from 'prop-types';
+import Helmet from 'react-helmet';
+import ClusterSysInfos from './ClusterSysInfos';
+import PageHeader from './PageHeader';
+import StandAloneSysInfos from './StandAloneSysInfos';
+import { translate } from '../../../helpers/l10n';
+import { getSystemInfo, SysInfo } from '../../../api/system';
+import { isCluster, parseQuery, Query, serializeQuery } from '../utils';
+import { RawQuery } from '../../../helpers/query';
+import '../styles.css';
+
+interface Props {
+ location: { pathname: string; query: RawQuery };
+}
+
+interface State {
+ loading: boolean;
+ sysInfoData?: SysInfo;
+}
+
+export default class App extends React.PureComponent<Props, State> {
+ mounted: boolean;
+ state: State = { loading: true };
+
+ static contextTypes = {
+ router: PropTypes.object
+ };
+
+ componentDidMount() {
+ this.mounted = true;
+ this.fetchSysInfo();
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ fetchSysInfo = () => {
+ this.setState({ loading: true });
+ getSystemInfo().then(
+ (sysInfoData: SysInfo) => {
+ if (this.mounted) {
+ this.setState({ loading: false, sysInfoData });
+ }
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ }
+ );
+ };
+
+ toggleSysInfoCards = (toggledCard: string) => {
+ const query = parseQuery(this.props.location.query);
+ let expandedCards;
+ if (query.expandedCards.includes(toggledCard)) {
+ expandedCards = query.expandedCards.filter(card => card !== toggledCard);
+ } else {
+ expandedCards = query.expandedCards.concat(toggledCard);
+ }
+ this.updateQuery({ expandedCards });
+ };
+
+ updateQuery = (newQuery: Query) => {
+ const query = serializeQuery({ ...parseQuery(this.props.location.query), ...newQuery });
+ this.context.router.push({ pathname: this.props.location.pathname, query });
+ };
+
+ renderSysInfo() {
+ const { sysInfoData } = this.state;
+ if (!sysInfoData) {
+ return null;
+ }
+
+ const query = parseQuery(this.props.location.query);
+ if (isCluster(sysInfoData)) {
+ return (
+ <ClusterSysInfos
+ sysInfoData={sysInfoData}
+ expandedCards={query.expandedCards}
+ toggleCard={this.toggleSysInfoCards}
+ />
+ );
+ }
+ return <StandAloneSysInfos sysInfoData={sysInfoData} />;
+ }
+
+ render() {
+ const { loading, sysInfoData } = this.state;
+ // TODO Correctly get logLevel, we are not sure yet how we want to do it for cluster mode
+ return (
+ <div className="page page-limited">
+ <Helmet title={translate('system_info.page')} />
+ <PageHeader
+ loading={loading}
+ isCluster={isCluster(sysInfoData)}
+ logLevel="INFO"
+ showActions={sysInfoData != undefined}
+ />
+ {this.renderSysInfo()}
+ </div>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import Modal from 'react-modal';
+import { setLogLevel } from '../../../api/system';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ infoMsg: string;
+ logLevel: string;
+ onChange: (level: string) => void;
+ onClose: () => void;
+}
+
+interface State {
+ newLevel: string;
+ updating: boolean;
+}
+
+const LOG_LEVELS = ['INFO', 'DEBUG', 'TRACE'];
+
+export default class ChangeLogLevelForm extends React.PureComponent<Props, State> {
+ constructor(props: Props) {
+ super(props);
+ this.state = { newLevel: props.logLevel, updating: false };
+ }
+
+ handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
+ event.preventDefault();
+ this.props.onClose();
+ };
+
+ handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ const { newLevel } = this.state;
+ if (!this.state.updating && newLevel !== this.props.logLevel) {
+ this.setState({ updating: true });
+ setLogLevel(newLevel).then(
+ () => this.props.onChange(newLevel),
+ () => this.setState({ updating: false })
+ );
+ }
+ };
+
+ handleLevelChange = (event: React.ChangeEvent<HTMLInputElement>) =>
+ this.setState({ newLevel: event.currentTarget.value });
+
+ render() {
+ const { updating, newLevel } = this.state;
+ const header = translate('system.set_log_level');
+ const disableSubmit = updating || newLevel === this.props.logLevel;
+ return (
+ <Modal
+ isOpen={true}
+ contentLabel={header}
+ className="modal"
+ overlayClassName="modal-overlay"
+ onRequestClose={this.props.onClose}>
+ <form id="set-log-level-form" onSubmit={this.handleFormSubmit}>
+ <div className="modal-head">
+ <h2>{header}</h2>
+ </div>
+ <div className="modal-body">
+ {LOG_LEVELS.map(level => (
+ <p key={level} className="spacer-bottom">
+ <input
+ type="radio"
+ className="spacer-right text-middle"
+ name="system.log_levels"
+ value={level}
+ checked={level === newLevel}
+ onChange={this.handleLevelChange}
+ />
+ {level}
+ </p>
+ ))}
+ <div className="alert alert-info spacer-top">{this.props.infoMsg}</div>
+ {newLevel !== 'INFO' && (
+ <div className="alert alert-danger spacer-top">
+ {translate('system.log_level.warning')}
+ </div>
+ )}
+ </div>
+ <div className="modal-foot">
+ {updating && <i className="spinner spacer-right" />}
+ <button disabled={disableSubmit} id="set-log-level-submit">
+ {translate('save')}
+ </button>
+ <a href="#" id="set-log-level-cancel" onClick={this.handleCancelClick}>
+ {translate('cancel')}
+ </a>
+ </div>
+ </form>
+ </Modal>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import { sortBy } from 'lodash';
+import HealthCard from './info-items/HealthCard';
+import { translate } from '../../../helpers/l10n';
+import {
+ getAppNodes,
+ getHealth,
+ getHealthCauses,
+ getMainCardSection,
+ getNodeName,
+ getSearchNodes,
+ ignoreInfoFields
+} from '../utils';
+import { SysInfo } from '../../../api/system';
+
+interface Props {
+ expandedCards: string[];
+ sysInfoData: SysInfo;
+ toggleCard: (toggledCard: string) => void;
+}
+
+export default function ClusterSysInfos({ expandedCards, sysInfoData, toggleCard }: Props) {
+ const mainCardName = 'System';
+ return (
+ <ul>
+ <HealthCard
+ biggerHealth={true}
+ health={getHealth(sysInfoData)}
+ healthCauses={getHealthCauses(sysInfoData)}
+ name={mainCardName}
+ onClick={toggleCard}
+ open={expandedCards.includes(mainCardName)}
+ sysInfoData={ignoreInfoFields(getMainCardSection(sysInfoData))}
+ />
+ <li className="note system-info-health-title">
+ {translate('system.application_nodes_title')}
+ </li>
+ {sortBy(getAppNodes(sysInfoData), 'name').map(node => (
+ <HealthCard
+ key={getNodeName(node)}
+ health={getHealth(node)}
+ healthCauses={getHealthCauses(node)}
+ name={getNodeName(node)}
+ onClick={toggleCard}
+ open={expandedCards.includes(getNodeName(node))}
+ sysInfoData={ignoreInfoFields(node)}
+ />
+ ))}
+ <li className="note system-info-health-title">{translate('system.search_nodes_title')}</li>
+ {sortBy(getSearchNodes(sysInfoData), 'name').map(node => (
+ <HealthCard
+ key={getNodeName(node)}
+ health={getHealth(node)}
+ healthCauses={getHealthCauses(node)}
+ name={getNodeName(node)}
+ onClick={toggleCard}
+ open={expandedCards.includes(getNodeName(node))}
+ sysInfoData={ignoreInfoFields(node)}
+ />
+ ))}
+ </ul>
+ );
+}
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import ChangeLogLevelForm from './ChangeLogLevelForm';
+import RestartForm from '../../../components/common/RestartForm';
+import { getBaseUrl } from '../../../helpers/urls';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ canDownloadLogs: boolean;
+ canRestart: boolean;
+ cluster: boolean;
+ logLevel: string;
+}
+
+interface State {
+ logLevel: string;
+ openLogsLevelForm: boolean;
+ openRestartForm: boolean;
+}
+
+export default class PageActions extends React.PureComponent<Props, State> {
+ constructor(props: Props) {
+ super(props);
+ this.state = {
+ openLogsLevelForm: false,
+ openRestartForm: false,
+ logLevel: props.logLevel
+ };
+ }
+
+ componentWillReceiveProps(nextProps: Props) {
+ if (nextProps.logLevel !== this.state.logLevel) {
+ this.setState({ logLevel: nextProps.logLevel });
+ }
+ }
+
+ handleLogsLevelOpen = (event: React.SyntheticEvent<HTMLElement>) => {
+ event.preventDefault();
+ this.setState({ openLogsLevelForm: true });
+ };
+
+ handleLogsLevelChange = (logLevel: string) => {
+ this.setState({ logLevel });
+ this.handleLogsLevelClose();
+ };
+
+ handleLogsLevelClose = () => this.setState({ openLogsLevelForm: false });
+
+ handleServerRestartOpen = () => this.setState({ openRestartForm: true });
+ handleServerRestartClose = () => this.setState({ openRestartForm: false });
+
+ render() {
+ const infoUrl = getBaseUrl() + '/api/system/info';
+ const logsUrl = getBaseUrl() + '/api/system/logs';
+ return (
+ <div className="page-actions">
+ <span>
+ {translate('system.logs_level')}
+ {':'}
+ <strong className="little-spacer-left">{this.state.logLevel}</strong>
+ <a
+ id="edit-logs-level-button"
+ className="spacer-left icon-edit"
+ href="#"
+ onClick={this.handleLogsLevelOpen}
+ />
+ </span>
+ {this.props.canDownloadLogs && (
+ <div className="display-inline-block dropdown spacer-left">
+ <button data-toggle="dropdown">
+ {translate('system.download_logs')}
+ <i className="icon-dropdown little-spacer-left" />
+ </button>
+ <ul className="dropdown-menu">
+ <li>
+ <a
+ href={logsUrl + '?process=app'}
+ id="logs-link"
+ download="sonarqube_app.log"
+ target="_blank">
+ Compute Engine
+ </a>
+ </li>
+ <li>
+ <a
+ href={logsUrl + '?process=ce'}
+ id="ce-logs-link"
+ download="sonarqube_ce.log"
+ target="_blank">
+ Main Process
+ </a>
+ </li>
+ <li>
+ <a
+ href={logsUrl + '?process=es'}
+ id="es-logs-link"
+ download="sonarqube_es.log"
+ target="_blank">
+ Elasticsearch
+ </a>
+ </li>
+ <li>
+ <a
+ href={logsUrl + '?process=web'}
+ id="web-logs-link"
+ download="sonarqube_web.log"
+ target="_blank">
+ Web Server
+ </a>
+ </li>
+ </ul>
+ </div>
+ )}
+ <a
+ href={infoUrl}
+ id="download-link"
+ className="button spacer-left"
+ download="sonarqube_system_info.json"
+ target="_blank">
+ {translate('system.download_system_info')}
+ </a>
+ {this.props.canRestart && (
+ <button
+ id="restart-server-button"
+ className="spacer-left"
+ onClick={this.handleServerRestartOpen}>
+ {translate('system.restart_server')}
+ </button>
+ )}
+ {this.props.canRestart &&
+ this.state.openRestartForm && <RestartForm onClose={this.handleServerRestartClose} />}
+ {this.state.openLogsLevelForm && (
+ <ChangeLogLevelForm
+ infoMsg={translate(
+ this.props.cluster ? 'system.cluster_log_level.info' : 'system.log_level.info'
+ )}
+ logLevel={this.state.logLevel}
+ onChange={this.handleLogsLevelChange}
+ onClose={this.handleLogsLevelClose}
+ />
+ )}
+ </div>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import PageActions from './PageActions';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ isCluster: boolean;
+ loading: boolean;
+ logLevel: string;
+ showActions: boolean;
+}
+
+export default function PageHeader({ isCluster, loading, logLevel, showActions }: Props) {
+ return (
+ <header className="page-header">
+ <h1 className="page-title">{translate('system_info.page')}</h1>
+ {showActions && (
+ <PageActions
+ canDownloadLogs={!isCluster}
+ canRestart={!isCluster}
+ cluster={isCluster}
+ logLevel={logLevel}
+ />
+ )}
+ {loading && (
+ <div className="page-actions">
+ <i className="spinner" />
+ </div>
+ )}
+ </header>
+ );
+}
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+
+interface Props {
+ sysInfoData: object;
+}
+
+export default class StandAloneSysInfos extends React.PureComponent<Props> {
+ render() {
+ return <div>StandAloneSysInfos</div>;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import ChangeLogLevelForm from '../ChangeLogLevelForm';
+
+it('should render correctly', () => {
+ expect(
+ shallow(
+ <ChangeLogLevelForm infoMsg="Foo" logLevel="INFO" onChange={() => {}} onClose={() => {}} />
+ )
+ ).toMatchSnapshot();
+});
+
+it('should display some warning messages for non INFO levels', () => {
+ expect(
+ shallow(
+ <ChangeLogLevelForm infoMsg="Foo" logLevel="DEBUG" onChange={() => {}} onClose={() => {}} />
+ )
+ ).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import ClusterSysInfos from '../ClusterSysInfos';
+import { HealthType, SysInfo } from '../../../../api/system';
+
+const sysInfoData: SysInfo = {
+ Cluster: true,
+ Health: HealthType.RED,
+ Name: 'Foo',
+ 'Health Causes': [{ message: 'Database down' }],
+ 'Application Nodes': [{ Name: 'Bar', Health: HealthType.GREEN, 'Health Causes': [] }],
+ 'Search Nodes': [{ Name: 'Baz', Health: HealthType.YELLOW, 'Health Causes': [] }]
+};
+
+it('should render correctly', () => {
+ expect(getWrapper()).toMatchSnapshot();
+});
+
+function getWrapper(props = {}) {
+ return shallow(
+ <ClusterSysInfos
+ expandedCards={['System', 'Foo']}
+ sysInfoData={sysInfoData}
+ toggleCard={() => {}}
+ {...props}
+ />
+ );
+}
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import PageActions from '../PageActions';
+import { click } from '../../../../helpers/testUtils';
+
+it('should render correctly', () => {
+ expect(
+ shallow(
+ <PageActions canDownloadLogs={true} canRestart={true} cluster={false} logLevel="INFO" />
+ )
+ ).toMatchSnapshot();
+});
+
+it('should render without restart and log download', () => {
+ expect(
+ shallow(
+ <PageActions canDownloadLogs={false} canRestart={false} cluster={true} logLevel="INFO" />
+ )
+ ).toMatchSnapshot();
+});
+
+it('should open restart modal', () => {
+ const wrapper = shallow(
+ <PageActions canDownloadLogs={true} canRestart={true} cluster={false} logLevel="INFO" />
+ );
+ click(wrapper.find('#restart-server-button'));
+ expect(wrapper.find('RestartForm')).toHaveLength(1);
+});
+
+it('should open change log level modal', () => {
+ const wrapper = shallow(
+ <PageActions canDownloadLogs={true} canRestart={true} cluster={false} logLevel="INFO" />
+ );
+ click(wrapper.find('#edit-logs-level-button'));
+ expect(wrapper.find('ChangeLogLevelForm')).toHaveLength(1);
+});
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import PageHeader from '../PageHeader';
+
+it('should render correctly', () => {
+ expect(
+ shallow(<PageHeader isCluster={true} loading={false} logLevel="INFO" showActions={true} />)
+ ).toMatchSnapshot();
+});
+
+it('should show a loading spinner and no actions', () => {
+ expect(
+ shallow(<PageHeader isCluster={true} loading={true} logLevel="INFO" showActions={false} />)
+ ).toMatchSnapshot();
+});
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should display some warning messages for non INFO levels 1`] = `
+<Modal
+ ariaHideApp={true}
+ bodyOpenClassName="ReactModal__Body--open"
+ className="modal"
+ closeTimeoutMS={0}
+ contentLabel="system.set_log_level"
+ isOpen={true}
+ onRequestClose={[Function]}
+ overlayClassName="modal-overlay"
+ parentSelector={[Function]}
+ portalClassName="ReactModalPortal"
+ shouldCloseOnOverlayClick={true}
+>
+ <form
+ id="set-log-level-form"
+ onSubmit={[Function]}
+ >
+ <div
+ className="modal-head"
+ >
+ <h2>
+ system.set_log_level
+ </h2>
+ </div>
+ <div
+ className="modal-body"
+ >
+ <p
+ className="spacer-bottom"
+ >
+ <input
+ checked={false}
+ className="spacer-right text-middle"
+ name="system.log_levels"
+ onChange={[Function]}
+ type="radio"
+ value="INFO"
+ />
+ INFO
+ </p>
+ <p
+ className="spacer-bottom"
+ >
+ <input
+ checked={true}
+ className="spacer-right text-middle"
+ name="system.log_levels"
+ onChange={[Function]}
+ type="radio"
+ value="DEBUG"
+ />
+ DEBUG
+ </p>
+ <p
+ className="spacer-bottom"
+ >
+ <input
+ checked={false}
+ className="spacer-right text-middle"
+ name="system.log_levels"
+ onChange={[Function]}
+ type="radio"
+ value="TRACE"
+ />
+ TRACE
+ </p>
+ <div
+ className="alert alert-info spacer-top"
+ >
+ Foo
+ </div>
+ <div
+ className="alert alert-danger spacer-top"
+ >
+ system.log_level.warning
+ </div>
+ </div>
+ <div
+ className="modal-foot"
+ >
+ <button
+ disabled={true}
+ id="set-log-level-submit"
+ >
+ save
+ </button>
+ <a
+ href="#"
+ id="set-log-level-cancel"
+ onClick={[Function]}
+ >
+ cancel
+ </a>
+ </div>
+ </form>
+</Modal>
+`;
+
+exports[`should render correctly 1`] = `
+<Modal
+ ariaHideApp={true}
+ bodyOpenClassName="ReactModal__Body--open"
+ className="modal"
+ closeTimeoutMS={0}
+ contentLabel="system.set_log_level"
+ isOpen={true}
+ onRequestClose={[Function]}
+ overlayClassName="modal-overlay"
+ parentSelector={[Function]}
+ portalClassName="ReactModalPortal"
+ shouldCloseOnOverlayClick={true}
+>
+ <form
+ id="set-log-level-form"
+ onSubmit={[Function]}
+ >
+ <div
+ className="modal-head"
+ >
+ <h2>
+ system.set_log_level
+ </h2>
+ </div>
+ <div
+ className="modal-body"
+ >
+ <p
+ className="spacer-bottom"
+ >
+ <input
+ checked={true}
+ className="spacer-right text-middle"
+ name="system.log_levels"
+ onChange={[Function]}
+ type="radio"
+ value="INFO"
+ />
+ INFO
+ </p>
+ <p
+ className="spacer-bottom"
+ >
+ <input
+ checked={false}
+ className="spacer-right text-middle"
+ name="system.log_levels"
+ onChange={[Function]}
+ type="radio"
+ value="DEBUG"
+ />
+ DEBUG
+ </p>
+ <p
+ className="spacer-bottom"
+ >
+ <input
+ checked={false}
+ className="spacer-right text-middle"
+ name="system.log_levels"
+ onChange={[Function]}
+ type="radio"
+ value="TRACE"
+ />
+ TRACE
+ </p>
+ <div
+ className="alert alert-info spacer-top"
+ >
+ Foo
+ </div>
+ </div>
+ <div
+ className="modal-foot"
+ >
+ <button
+ disabled={true}
+ id="set-log-level-submit"
+ >
+ save
+ </button>
+ <a
+ href="#"
+ id="set-log-level-cancel"
+ onClick={[Function]}
+ >
+ cancel
+ </a>
+ </div>
+ </form>
+</Modal>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<ul>
+ <HealthCard
+ biggerHealth={true}
+ health="RED"
+ healthCauses={
+ Array [
+ Object {
+ "message": "Database down",
+ },
+ ]
+ }
+ name="System"
+ onClick={[Function]}
+ open={true}
+ sysInfoData={
+ Object {
+ "Name": "Foo",
+ }
+ }
+ />
+ <li
+ className="note system-info-health-title"
+ >
+ system.application_nodes_title
+ </li>
+ <HealthCard
+ health="GREEN"
+ healthCauses={Array []}
+ name="Bar"
+ onClick={[Function]}
+ open={false}
+ sysInfoData={
+ Object {
+ "Name": "Bar",
+ }
+ }
+ />
+ <li
+ className="note system-info-health-title"
+ >
+ system.search_nodes_title
+ </li>
+ <HealthCard
+ health="YELLOW"
+ healthCauses={Array []}
+ name="Baz"
+ onClick={[Function]}
+ open={false}
+ sysInfoData={
+ Object {
+ "Name": "Baz",
+ }
+ }
+ />
+</ul>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<div
+ className="page-actions"
+>
+ <span>
+ system.logs_level
+ :
+ <strong
+ className="little-spacer-left"
+ >
+ INFO
+ </strong>
+ <a
+ className="spacer-left icon-edit"
+ href="#"
+ id="edit-logs-level-button"
+ onClick={[Function]}
+ />
+ </span>
+ <div
+ className="display-inline-block dropdown spacer-left"
+ >
+ <button
+ data-toggle="dropdown"
+ >
+ system.download_logs
+ <i
+ className="icon-dropdown little-spacer-left"
+ />
+ </button>
+ <ul
+ className="dropdown-menu"
+ >
+ <li>
+ <a
+ download="sonarqube_app.log"
+ href="/api/system/logs?process=app"
+ id="logs-link"
+ target="_blank"
+ >
+ Compute Engine
+ </a>
+ </li>
+ <li>
+ <a
+ download="sonarqube_ce.log"
+ href="/api/system/logs?process=ce"
+ id="ce-logs-link"
+ target="_blank"
+ >
+ Main Process
+ </a>
+ </li>
+ <li>
+ <a
+ download="sonarqube_es.log"
+ href="/api/system/logs?process=es"
+ id="es-logs-link"
+ target="_blank"
+ >
+ Elasticsearch
+ </a>
+ </li>
+ <li>
+ <a
+ download="sonarqube_web.log"
+ href="/api/system/logs?process=web"
+ id="web-logs-link"
+ target="_blank"
+ >
+ Web Server
+ </a>
+ </li>
+ </ul>
+ </div>
+ <a
+ className="button spacer-left"
+ download="sonarqube_system_info.json"
+ href="/api/system/info"
+ id="download-link"
+ target="_blank"
+ >
+ system.download_system_info
+ </a>
+ <button
+ className="spacer-left"
+ id="restart-server-button"
+ onClick={[Function]}
+ >
+ system.restart_server
+ </button>
+</div>
+`;
+
+exports[`should render without restart and log download 1`] = `
+<div
+ className="page-actions"
+>
+ <span>
+ system.logs_level
+ :
+ <strong
+ className="little-spacer-left"
+ >
+ INFO
+ </strong>
+ <a
+ className="spacer-left icon-edit"
+ href="#"
+ id="edit-logs-level-button"
+ onClick={[Function]}
+ />
+ </span>
+ <a
+ className="button spacer-left"
+ download="sonarqube_system_info.json"
+ href="/api/system/info"
+ id="download-link"
+ target="_blank"
+ >
+ system.download_system_info
+ </a>
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<header
+ className="page-header"
+>
+ <h1
+ className="page-title"
+ >
+ system_info.page
+ </h1>
+ <PageActions
+ canDownloadLogs={false}
+ canRestart={false}
+ cluster={true}
+ logLevel="INFO"
+ />
+</header>
+`;
+
+exports[`should show a loading spinner and no actions 1`] = `
+<header
+ className="page-header"
+>
+ <h1
+ className="page-title"
+ >
+ system_info.page
+ </h1>
+ <div
+ className="page-actions"
+ >
+ <i
+ className="spinner"
+ />
+ </div>
+</header>
+`;
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import * as classNames from 'classnames';
+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 { groupSections } from '../../utils';
+
+interface Props {
+ biggerHealth?: boolean;
+ health: HealthType;
+ healthCauses: HealthCause[];
+ onClick: (toggledCard: string) => void;
+ open: boolean;
+ name: string;
+ sysInfoData: SysValueObject;
+}
+
+interface State {
+ hoveringDetail: boolean;
+}
+
+export default class HealthCard extends React.PureComponent<Props, State> {
+ state: State = { hoveringDetail: false };
+
+ handleClick = () => this.props.onClick(this.props.name);
+ onDetailEnter = () => this.setState({ hoveringDetail: true });
+ onDetailLeave = () => this.setState({ hoveringDetail: false });
+
+ render() {
+ const { open, sysInfoData } = this.props;
+ const { mainSection, sections } = groupSections(sysInfoData);
+ const showFields = open && mainSection && Object.keys(mainSection).length > 0;
+ const showSections = open && sections;
+ return (
+ <li
+ className={classNames('boxed-group system-info-health-card', {
+ 'no-hover': this.state.hoveringDetail
+ })}>
+ <div className="boxed-group-header" onClick={this.handleClick}>
+ <span className="system-info-health-card-title">
+ <OpenCloseIcon className="little-spacer-right" open={open} />
+ {this.props.name}
+ </span>
+ <HealthItem
+ className={classNames('pull-right', { 'big-dot': this.props.biggerHealth })}
+ health={this.props.health}
+ healthCauses={this.props.healthCauses}
+ />
+ </div>
+ {open && (
+ <div
+ className="boxed-group-inner"
+ onMouseEnter={this.onDetailEnter}
+ onMouseLeave={this.onDetailLeave}>
+ {showFields && <Section items={mainSection} />}
+ {showSections &&
+ map(sections, (section, name) => <Section key={name} items={section} name={name} />)}
+ </div>
+ )}
+ </li>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import * as classNames from 'classnames';
+import { HealthCause, HealthType } from '../../../../api/system';
+
+interface Props {
+ className?: string;
+ health: HealthType;
+ healthCause: HealthCause;
+}
+
+export default function HealthCauseItem({ className, health, healthCause }: Props) {
+ return (
+ <span
+ className={classNames(
+ 'alert',
+ health === HealthType.RED ? 'alert-danger' : 'alert-warning',
+ className
+ )}>
+ {healthCause.message}
+ </span>
+ );
+}
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import * as classNames from 'classnames';
+import HealthCauseItem from './HealthCauseItem';
+import { HealthType, HealthCause } from '../../../../api/system';
+
+interface Props {
+ className?: string;
+ health: HealthType;
+ healthCauses?: HealthCause[];
+}
+
+export default function HealthItem({ className, health, healthCauses }: Props) {
+ const hasHealthCauses = healthCauses && healthCauses.length > 0 && health !== HealthType.GREEN;
+ return (
+ <div className={classNames('system-info-health-info', className)}>
+ {hasHealthCauses &&
+ healthCauses!.map((cause, idx) => (
+ <HealthCauseItem key={idx} className="spacer-right" health={health} healthCause={cause} />
+ ))}
+ <span className={classNames('system-info-health-dot', health)} />
+ </div>
+ );
+}
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import { map } from 'lodash';
+import SysInfoItem from './SysInfoItem';
+import { SysValueObject } from '../../../../api/system';
+
+interface Props {
+ name?: string;
+ items: SysValueObject;
+}
+
+export default function Section({ name, items }: Props) {
+ return (
+ <div className="system-info-section">
+ {name && <h4 className="spacer-bottom">{name}</h4>}
+ <table className="data zebra" id={name}>
+ <tbody>
+ {map(items, (value, name) => {
+ return (
+ <tr key={name}>
+ <td className="thin">
+ <div className="system-info-section-item-name">{name}</div>
+ </td>
+ <td style={{ wordBreak: 'break-all' }}>
+ <SysInfoItem name={name} value={value} />
+ </td>
+ </tr>
+ );
+ })}
+ </tbody>
+ </table>
+ </div>
+ );
+}
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import { map } from 'lodash';
+import HealthItem from './HealthItem';
+import { HealthType, SysValue, SysValueObject } from '../../../../api/system';
+import { HEALTH_FIELD } from '../../utils';
+
+interface Props {
+ name: string;
+ value: SysValue;
+}
+
+export default function SysInfoItem({ name, value }: Props): JSX.Element {
+ if (name === HEALTH_FIELD) {
+ return <HealthItem className="no-margin" health={value as HealthType} />;
+ }
+ if (value instanceof Array) {
+ return <code>{JSON.stringify(value)}</code>;
+ }
+ switch (typeof value) {
+ case 'boolean':
+ return <BooleanItem value={value as boolean} />;
+ case 'object':
+ return <ObjectItem value={value as SysValueObject} />;
+ default:
+ return <code>{value}</code>;
+ }
+}
+
+function BooleanItem({ value }: { value: boolean }) {
+ if (value) {
+ return <i className="icon-check" />;
+ } else {
+ return <i className="icon-delete" />;
+ }
+}
+
+function ObjectItem({ value }: { value: SysValueObject }) {
+ return (
+ <table className="data">
+ <tbody>
+ {map(value, (value, name) => (
+ <tr key={name}>
+ <td className="thin nowrap">{name}</td>
+ <td>
+ <SysInfoItem name={name} value={value} />
+ </td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ );
+}
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import HealthCard from '../HealthCard';
+import { click } from '../../../../../helpers/testUtils';
+import { HealthType } from '../../../../../api/system';
+
+it('should render correctly', () => {
+ expect(getShallowWrapper()).toMatchSnapshot();
+});
+
+it('should display the sysinfo detail', () => {
+ expect(getShallowWrapper({ biggerHealth: true, open: true })).toMatchSnapshot();
+});
+
+it('should show the sysinfo detail when the card is clicked', () => {
+ const onClick = jest.fn();
+ click(getShallowWrapper({ onClick }).find('.boxed-group-header'));
+ expect(onClick).toBeCalled();
+ expect(onClick).toBeCalledWith('Foobar');
+});
+
+it('should show a main section and multiple sub sections', () => {
+ const sysInfoData = {
+ Name: 'foo',
+ bar: 'Bar',
+ Database: { db: 'test' },
+ Elasticseach: { Elastic: 'search' }
+ };
+ expect(getShallowWrapper({ open: true, sysInfoData })).toMatchSnapshot();
+});
+
+function getShallowWrapper(props = {}) {
+ return shallow(
+ <HealthCard
+ biggerHealth={false}
+ health={HealthType.RED}
+ healthCauses={[{ message: 'foo' }]}
+ name="Foobar"
+ onClick={() => {}}
+ open={false}
+ sysInfoData={{}}
+ {...props}
+ />
+ );
+}
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import HealthCauseItem from '../HealthCauseItem';
+import { HealthType } from '../../../../../api/system';
+
+it('should render correctly', () => {
+ expect(
+ shallow(<HealthCauseItem health={HealthType.RED} healthCause={{ message: 'foo' }} />)
+ ).toMatchSnapshot();
+ expect(
+ shallow(<HealthCauseItem health={HealthType.YELLOW} healthCause={{ message: 'foo' }} />)
+ ).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import HealthItem from '../HealthItem';
+import { HealthType } from '../../../../../api/system';
+
+it('should render correctly', () => {
+ expect(
+ shallow(<HealthItem health={HealthType.RED} healthCauses={[{ message: 'foo' }]} />)
+ ).toMatchSnapshot();
+});
+
+it('should not render health causes', () => {
+ expect(
+ shallow(<HealthItem health={HealthType.GREEN} healthCauses={[{ message: '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' }]}
+ />
+ )
+ ).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import Section from '../Section';
+
+it('should render correctly', () => {
+ expect(
+ shallow(<Section name="foo" items={{ foo: 1, bar: 'Bar', baz: false }} />)
+ ).toMatchSnapshot();
+});
+
+it('should not render a title', () => {
+ expect(shallow(<Section items={{ foo: 'bar' }} />)).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import { shallow, mount } from 'enzyme';
+import SysInfoItem from '../SysInfoItem';
+
+it('should render string', () => {
+ const wrapper = shallow(<SysInfoItem name="foo" value="/some/path/as/an/example" />);
+ expect(wrapper.find('code').text()).toBe('/some/path/as/an/example');
+});
+
+it('should render object', () => {
+ const wrapper = shallow(<SysInfoItem name="foo" value={{ bar: 'baz' }} />);
+ expect(wrapper.find('ObjectItem').prop('value')).toEqual({ bar: 'baz' });
+});
+
+it('should render boolean', () => {
+ const wrapper = shallow(<SysInfoItem name="foo" value={true} />);
+ expect(wrapper.find('BooleanItem').prop('value')).toBe(true);
+});
+
+it('should render health item', () => {
+ const wrapper = shallow(<SysInfoItem name="Health" value="GREEN" />);
+ expect(wrapper.find('HealthItem').prop('health')).toBe('GREEN');
+});
+
+it('should render object correctly', () => {
+ expect(
+ mount(
+ <SysInfoItem name="test" value={{ foo: 'Far', bar: { a: 1, b: 'b' }, baz: true }} />
+ ).find('ObjectItem')
+ ).toMatchSnapshot();
+});
+
+it('should render `true`', () => {
+ const wrapper = mount(<SysInfoItem name="test" value={true} />);
+ expect(wrapper.find('.icon-check')).toHaveLength(1);
+});
+
+it('should render `false`', () => {
+ const wrapper = mount(<SysInfoItem name="test" value={false} />);
+ expect(wrapper.find('.icon-delete')).toHaveLength(1);
+});
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should display the sysinfo detail 1`] = `
+<li
+ className="boxed-group system-info-health-card"
+>
+ <div
+ className="boxed-group-header"
+ onClick={[Function]}
+ >
+ <span
+ className="system-info-health-card-title"
+ >
+ <OpenCloseIcon
+ className="little-spacer-right"
+ open={true}
+ />
+ Foobar
+ </span>
+ <HealthItem
+ className="pull-right big-dot"
+ health="RED"
+ healthCauses={
+ Array [
+ Object {
+ "message": "foo",
+ },
+ ]
+ }
+ />
+ </div>
+ <div
+ className="boxed-group-inner"
+ onMouseEnter={[Function]}
+ onMouseLeave={[Function]}
+ />
+</li>
+`;
+
+exports[`should render correctly 1`] = `
+<li
+ className="boxed-group system-info-health-card"
+>
+ <div
+ className="boxed-group-header"
+ onClick={[Function]}
+ >
+ <span
+ className="system-info-health-card-title"
+ >
+ <OpenCloseIcon
+ className="little-spacer-right"
+ open={false}
+ />
+ Foobar
+ </span>
+ <HealthItem
+ className="pull-right"
+ health="RED"
+ healthCauses={
+ Array [
+ Object {
+ "message": "foo",
+ },
+ ]
+ }
+ />
+ </div>
+</li>
+`;
+
+exports[`should show a main section and multiple sub sections 1`] = `
+<li
+ className="boxed-group system-info-health-card"
+>
+ <div
+ className="boxed-group-header"
+ onClick={[Function]}
+ >
+ <span
+ className="system-info-health-card-title"
+ >
+ <OpenCloseIcon
+ className="little-spacer-right"
+ open={true}
+ />
+ Foobar
+ </span>
+ <HealthItem
+ className="pull-right"
+ health="RED"
+ healthCauses={
+ Array [
+ Object {
+ "message": "foo",
+ },
+ ]
+ }
+ />
+ </div>
+ <div
+ className="boxed-group-inner"
+ onMouseEnter={[Function]}
+ onMouseLeave={[Function]}
+ >
+ <Section
+ items={
+ Object {
+ "Name": "foo",
+ "bar": "Bar",
+ }
+ }
+ />
+ <Section
+ items={
+ Object {
+ "db": "test",
+ }
+ }
+ name="Database"
+ />
+ <Section
+ items={
+ Object {
+ "Elastic": "search",
+ }
+ }
+ name="Elasticseach"
+ />
+ </div>
+</li>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<span
+ className="alert alert-danger"
+>
+ foo
+</span>
+`;
+
+exports[`should render correctly 2`] = `
+<span
+ className="alert alert-warning"
+>
+ foo
+</span>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should not render health causes 1`] = `
+<div
+ className="system-info-health-info"
+>
+ <span
+ className="system-info-health-dot GREEN"
+ />
+</div>
+`;
+
+exports[`should not render health causes 2`] = `
+<div
+ className="system-info-health-info"
+>
+ <span
+ className="system-info-health-dot YELLOW"
+ />
+</div>
+`;
+
+exports[`should render correctly 1`] = `
+<div
+ className="system-info-health-info"
+>
+ <HealthCauseItem
+ className="spacer-right"
+ health="RED"
+ healthCause={
+ Object {
+ "message": "foo",
+ }
+ }
+ />
+ <span
+ className="system-info-health-dot RED"
+ />
+</div>
+`;
+
+exports[`should render multiple health causes 1`] = `
+<div
+ className="system-info-health-info"
+>
+ <HealthCauseItem
+ className="spacer-right"
+ health="YELLOW"
+ healthCause={
+ Object {
+ "message": "foo",
+ }
+ }
+ />
+ <HealthCauseItem
+ className="spacer-right"
+ health="YELLOW"
+ healthCause={
+ Object {
+ "message": "bar",
+ }
+ }
+ />
+ <span
+ className="system-info-health-dot YELLOW"
+ />
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should not render a title 1`] = `
+<div
+ className="system-info-section"
+>
+ <table
+ className="data zebra"
+ >
+ <tbody>
+ <tr>
+ <td
+ className="thin"
+ >
+ <div
+ className="system-info-section-item-name"
+ >
+ foo
+ </div>
+ </td>
+ <td
+ style={
+ Object {
+ "wordBreak": "break-all",
+ }
+ }
+ >
+ <SysInfoItem
+ name="foo"
+ value="bar"
+ />
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</div>
+`;
+
+exports[`should render correctly 1`] = `
+<div
+ className="system-info-section"
+>
+ <h4
+ className="spacer-bottom"
+ >
+ foo
+ </h4>
+ <table
+ className="data zebra"
+ id="foo"
+ >
+ <tbody>
+ <tr>
+ <td
+ className="thin"
+ >
+ <div
+ className="system-info-section-item-name"
+ >
+ foo
+ </div>
+ </td>
+ <td
+ style={
+ Object {
+ "wordBreak": "break-all",
+ }
+ }
+ >
+ <SysInfoItem
+ name="foo"
+ value={1}
+ />
+ </td>
+ </tr>
+ <tr>
+ <td
+ className="thin"
+ >
+ <div
+ className="system-info-section-item-name"
+ >
+ bar
+ </div>
+ </td>
+ <td
+ style={
+ Object {
+ "wordBreak": "break-all",
+ }
+ }
+ >
+ <SysInfoItem
+ name="bar"
+ value="Bar"
+ />
+ </td>
+ </tr>
+ <tr>
+ <td
+ className="thin"
+ >
+ <div
+ className="system-info-section-item-name"
+ >
+ baz
+ </div>
+ </td>
+ <td
+ style={
+ Object {
+ "wordBreak": "break-all",
+ }
+ }
+ >
+ <SysInfoItem
+ name="baz"
+ value={false}
+ />
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render object correctly 1`] = `
+Array [
+ <ObjectItem
+ value={
+ Object {
+ "bar": Object {
+ "a": 1,
+ "b": "b",
+ },
+ "baz": true,
+ "foo": "Far",
+ }
+ }
+>
+ <table
+ className="data"
+ >
+ <tbody>
+ <tr>
+ <td
+ className="thin nowrap"
+ >
+ foo
+ </td>
+ <td>
+ <SysInfoItem
+ name="foo"
+ value="Far"
+ >
+ <code>
+ Far
+ </code>
+ </SysInfoItem>
+ </td>
+ </tr>
+ <tr>
+ <td
+ className="thin nowrap"
+ >
+ bar
+ </td>
+ <td>
+ <SysInfoItem
+ name="bar"
+ value={
+ Object {
+ "a": 1,
+ "b": "b",
+ }
+ }
+ >
+ <ObjectItem
+ value={
+ Object {
+ "a": 1,
+ "b": "b",
+ }
+ }
+ >
+ <table
+ className="data"
+ >
+ <tbody>
+ <tr>
+ <td
+ className="thin nowrap"
+ >
+ a
+ </td>
+ <td>
+ <SysInfoItem
+ name="a"
+ value={1}
+ >
+ <code>
+ 1
+ </code>
+ </SysInfoItem>
+ </td>
+ </tr>
+ <tr>
+ <td
+ className="thin nowrap"
+ >
+ b
+ </td>
+ <td>
+ <SysInfoItem
+ name="b"
+ value="b"
+ >
+ <code>
+ b
+ </code>
+ </SysInfoItem>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </ObjectItem>
+ </SysInfoItem>
+ </td>
+ </tr>
+ <tr>
+ <td
+ className="thin nowrap"
+ >
+ baz
+ </td>
+ <td>
+ <SysInfoItem
+ name="baz"
+ value={true}
+ >
+ <BooleanItem
+ value={true}
+ >
+ <i
+ className="icon-check"
+ />
+ </BooleanItem>
+ </SysInfoItem>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</ObjectItem>,
+ <ObjectItem
+ value={
+ Object {
+ "a": 1,
+ "b": "b",
+ }
+ }
+>
+ <table
+ className="data"
+ >
+ <tbody>
+ <tr>
+ <td
+ className="thin nowrap"
+ >
+ a
+ </td>
+ <td>
+ <SysInfoItem
+ name="a"
+ value={1}
+ >
+ <code>
+ 1
+ </code>
+ </SysInfoItem>
+ </td>
+ </tr>
+ <tr>
+ <td
+ className="thin nowrap"
+ >
+ b
+ </td>
+ <td>
+ <SysInfoItem
+ name="b"
+ value="b"
+ >
+ <code>
+ b
+ </code>
+ </SysInfoItem>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+</ObjectItem>,
+]
+`;
import { getSystemInfo } from '../../api/system';
import Section from './section';
import { translate } from '../../helpers/l10n';
-import RestartModal from '../../components/RestartModal';
+import RestartForm from '../../components/common/RestartForm';
const SECTIONS_ORDER = [
'SonarQube',
];
export default class Main extends React.PureComponent {
+ state = { openRestartForm: false };
+
componentDidMount() {
getSystemInfo().then(info => this.setState({ sections: this.parseSections(info) }));
}
orderItems = items => sortBy(items, 'name');
- handleServerRestart = () => {
- new RestartModal().render();
- };
+ handleServerRestartOpen = () => this.setState({ openRestartForm: true });
+ handleServerRestartClose = () => this.setState({ openRestartForm: false });
render() {
let sections = null;
<button
id="restart-server-button"
className="big-spacer-left"
- onClick={this.handleServerRestart}>
+ onClick={this.handleServerRestartOpen}>
Restart Server
</button>
+ {this.state.openRestartForm && <RestartForm onClose={this.handleServerRestartClose} />}
</div>
</header>
{sections}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { RouterState, IndexRouteProps } from 'react-router';
+import { RouterState, RouteComponent, IndexRouteProps } from 'react-router';
const routes = [
{
getIndexRoute(_: RouterState, callback: (err: any, route: IndexRouteProps) => any) {
- import('./main').then(i => callback(null, { component: (i as any).default }));
+ import('./components/App').then(i => callback(null, { component: i.default }));
+ }
+ },
+ {
+ path: 'old',
+ getComponent(_: RouterState, callback: (err: any, component: RouteComponent) => any) {
+ import('./main').then(i => callback(null, (i as any).default));
}
}
];
--- /dev/null
+.system-info-health-title {
+ margin-top: 24px;
+ margin-bottom: 16px;
+}
+
+.system-info-health-card {
+ margin-bottom: 8px;
+ transition: border-color 0.3s ease;
+}
+
+.system-info-health-card:not(.no-hover):hover {
+ border-color: #4b9fd5;
+}
+
+.system-info-health-card:not(.no-hover):hover .system-info-health-card-title {
+ color: #4b9fd5;
+}
+
+.system-info-health-card .boxed-group-header {
+ cursor: pointer;
+ padding-bottom: 15px;
+}
+
+.system-info-health-card .boxed-group-inner {
+ padding-top: 0;
+}
+
+.system-info-health-card-title {
+ font-weight: bold;
+}
+
+.system-info-health-info {
+ margin-top: -4px;
+}
+
+.system-info-health-dot {
+ display: inline-block;
+ width: 16px;
+ height: 16px;
+ margin: 4px;
+ border-radius: 16px;
+ box-sizing: border-box;
+}
+
+.system-info-health-dot.GREEN {
+ background-color: #00aa00;
+}
+
+.system-info-health-dot.YELLOW {
+ background-color: #eabe06;
+}
+.system-info-health-dot.RED {
+ background-color: #d4333f;
+}
+
+.system-info-health-info .alert {
+ display: inline-block;
+ position: relative;
+ top: -8px;
+}
+
+.system-info-health-info.big-dot .system-info-health-dot {
+ width: 24px;
+ height: 24px;
+ margin: 0;
+ border-radius: 24px;
+}
+
+.system-info-health-info.no-margin .system-info-health-dot {
+ margin: 0;
+}
+
+.system-info-section ~ .system-info-section {
+ margin-top: 16px;
+}
+
+.system-info-section-item-name {
+ width: 25vw;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
--- /dev/null
+/*
+ * 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.
+ */
+import { each, omit, memoize } from 'lodash';
+import {
+ cleanQuery,
+ parseAsArray,
+ parseAsString,
+ RawQuery,
+ serializeStringArray
+} from '../../helpers/query';
+import {
+ HealthCause,
+ HealthType,
+ NodeInfo,
+ SysInfo,
+ SysInfoSection,
+ SysValueObject
+} from '../../api/system';
+
+export interface Query {
+ expandedCards: string[];
+}
+
+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]);
+}
+
+export function getAppNodes(sysInfoData: SysInfo): NodeInfo[] {
+ return sysInfoData['Application Nodes'];
+}
+
+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 getMainCardSection(sysInfoData: SysInfo): SysValueObject {
+ return omit(sysInfoData, ['Application Nodes', 'Search Nodes', 'Settings', 'Statistics']);
+}
+
+export function getNodeName(nodeInfo: NodeInfo): string {
+ return nodeInfo['Name'];
+}
+
+export function getSearchNodes(sysInfoData: SysInfo): NodeInfo[] {
+ return sysInfoData['Search Nodes'];
+}
+
+export function groupSections(sysInfoData: SysValueObject) {
+ let mainSection: SysValueObject = {};
+ let sections: SysInfoSection = {};
+ each(sysInfoData, (item, key) => {
+ if (typeof item !== 'object' || item instanceof Array) {
+ mainSection[key] = item;
+ } else {
+ sections[key] = item;
+ }
+ });
+ return { mainSection, sections };
+}
+
+export function isCluster(sysInfoData?: SysInfo): boolean {
+ return sysInfoData != undefined && sysInfoData['Cluster'];
+}
+
+export const parseQuery = memoize((urlQuery: RawQuery): Query => {
+ return {
+ expandedCards: parseAsArray(urlQuery.expand, parseAsString)
+ };
+});
+
+export const serializeQuery = memoize((query: Query): RawQuery => {
+ return cleanQuery({
+ expand: serializeStringArray(query.expandedCards)
+ });
+});
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+import * as classNames from 'classnames';
+import Modal from 'react-modal';
+import { restartAndWait } from '../../api/system';
+import { translate } from '../../helpers/l10n';
+
+interface Props {
+ onClose: () => void;
+}
+
+interface State {
+ restarting: boolean;
+}
+
+export default class RestartForm extends React.PureComponent<Props, State> {
+ state: State = { restarting: false };
+
+ handleCancelClick = (event: React.SyntheticEvent<HTMLElement>) => {
+ event.preventDefault();
+ this.props.onClose();
+ };
+
+ handleFormSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ if (!this.state.restarting) {
+ this.setState({ restarting: true });
+ restartAndWait().then(
+ () => document.location.reload(),
+ () => this.setState({ restarting: false })
+ );
+ }
+ };
+
+ render() {
+ const { restarting } = this.state;
+ const header = translate('system.restart_server');
+ return (
+ <Modal
+ isOpen={true}
+ contentLabel={header}
+ className="modal"
+ overlayClassName="modal-overlay"
+ onRequestClose={this.props.onClose}>
+ <form id="restart-form" onSubmit={this.handleFormSubmit}>
+ <div className="modal-head">
+ <h2>{header}</h2>
+ </div>
+ <div className="modal-body">
+ <p className={classNames('spacer-top spacer-bottom', { 'text-center': restarting })}>
+ {translate(restarting ? 'system.is_restarting' : 'system.are_you_sure_to_restart')}
+ </p>
+ {restarting && (
+ <p className="big-spacer-top spacer-bottom text-center">
+ <i className="spinner" />
+ </p>
+ )}
+ </div>
+ {!restarting && (
+ <div className="modal-foot">
+ <button id="restart-server-submit">{translate('restart')}</button>
+ <a
+ href="#"
+ className="js-modal-close"
+ id="restart-server-cancel"
+ onClick={this.handleCancelClick}>
+ {translate('cancel')}
+ </a>
+ </div>
+ )}
+ </form>
+ </Modal>
+ );
+ }
+}
// @flow
/* eslint-disable max-len */
import React from 'react';
-import Tooltip from '../controls/Tooltip';
+import OpenCloseIcon from '../icons-components/OpenCloseIcon';
import HelpIcon from '../icons-components/HelpIcon';
+import Tooltip from '../controls/Tooltip';
import { translate } from '../../helpers/l10n';
/*::
}
};
- renderCheckbox() {
- return (
- <svg
- className="little-spacer-right"
- viewBox="0 0 1792 1792"
- width="10"
- height="10"
- style={{ paddingTop: 3 }}>
- {this.props.open ? (
- <path
- style={{ fill: 'currentColor ' }}
- d="M1683 808l-742 741q-19 19-45 19t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"
- />
- ) : (
- <path
- style={{ fill: 'currentColor ' }}
- d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
- />
- )}
- </svg>
- );
- }
-
renderHelper() {
if (!this.props.helper) {
return null;
{this.props.onClick ? (
<span className="search-navigator-facet-header">
<a href="#" onClick={this.handleClick}>
- {this.renderCheckbox()}
+ <OpenCloseIcon className="little-spacer-right" open={this.props.open} />
{this.props.name}
</a>
{this.renderHelper()}
href="#"
onClick={[Function]}
>
- <svg
+ <OpenCloseIcon
className="little-spacer-right"
- height="10"
- style={
- Object {
- "paddingTop": 3,
- }
- }
- viewBox="0 0 1792 1792"
- width="10"
- >
- <path
- d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
- style={
- Object {
- "fill": "currentColor ",
- }
- }
- />
- </svg>
+ open={false}
+ />
foo
</a>
<span
href="#"
onClick={[Function]}
>
- <svg
+ <OpenCloseIcon
className="little-spacer-right"
- height="10"
- style={
- Object {
- "paddingTop": 3,
- }
- }
- viewBox="0 0 1792 1792"
- width="10"
- >
- <path
- d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
- style={
- Object {
- "fill": "currentColor ",
- }
- }
- />
- </svg>
+ open={false}
+ />
foo
</a>
<span
href="#"
onClick={[Function]}
>
- <svg
+ <OpenCloseIcon
className="little-spacer-right"
- height="10"
- style={
- Object {
- "paddingTop": 3,
- }
- }
- viewBox="0 0 1792 1792"
- width="10"
- >
- <path
- d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
- style={
- Object {
- "fill": "currentColor ",
- }
- }
- />
- </svg>
+ open={false}
+ />
foo
</a>
</span>
href="#"
onClick={[Function]}
>
- <svg
+ <OpenCloseIcon
className="little-spacer-right"
- height="10"
- style={
- Object {
- "paddingTop": 3,
- }
- }
- viewBox="0 0 1792 1792"
- width="10"
- >
- <path
- d="M1683 808l-742 741q-19 19-45 19t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"
- style={
- Object {
- "fill": "currentColor ",
- }
- }
- />
- </svg>
+ open={true}
+ />
foo
</a>
</span>
href="#"
onClick={[Function]}
>
- <svg
+ <OpenCloseIcon
className="little-spacer-right"
- height="10"
- style={
- Object {
- "paddingTop": 3,
- }
- }
- viewBox="0 0 1792 1792"
- width="10"
- >
- <path
- d="M1683 808l-742 741q-19 19-45 19t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"
- style={
- Object {
- "fill": "currentColor ",
- }
- }
- />
- </svg>
+ open={true}
+ />
foo
</a>
</span>
--- /dev/null
+/*
+ * 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.
+ */
+import * as React from 'react';
+
+interface Props {
+ className?: string;
+ open: boolean;
+ size?: number;
+}
+
+export default function OpenCloseIcon({ className, open, size = 14 }: Props) {
+ return (
+ <svg
+ className={className}
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 16 16"
+ width={size}
+ height={size}
+ style={{ fill: 'currentColor' }}>
+ {open ? (
+ <path d="M13.506 8.539l-5.191 5.184q-0.133 0.133-0.315 0.133t-0.315-0.133l-5.191-5.184q-0.133-0.133-0.133-0.318t0.133-0.318l1.161-1.154q0.133-0.133 0.315-0.133t0.315 0.133l3.715 3.715 3.715-3.715q0.133-0.133 0.315-0.133t0.315 0.133l1.161 1.154q0.133 0.133 0.133 0.318t-0.133 0.318z" />
+ ) : (
+ <path d="M13.527 8.318l-5.244 5.244q-0.134 0.134-0.318 0.134t-0.318-0.134l-1.173-1.173q-0.134-0.134-0.134-0.318t0.134-0.318l3.753-3.753-3.753-3.753q-0.134-0.134-0.134-0.318t0.134-0.318l1.173-1.173q0.134-0.134 0.318-0.134t0.318 0.134l5.244 5.244q0.134 0.134 0.134 0.318t-0.134 0.318z" />
+ )}
+ </svg>
+ );
+}
import _HistoryIcon from './HistoryIcon';
import _LinkIcon from './LinkIcon';
import _ListIcon from './ListIcon';
+import _OpenCloseIcon from './OpenCloseIcon';
import _OrganizationIcon from './OrganizationIcon';
import _ProjectEventIcon from './ProjectEventIcon';
import _QualifierIcon from './QualifierIcon';
export const HistoryIcon = _HistoryIcon;
export const LinkIcon = _LinkIcon;
export const ListIcon = _ListIcon;
+export const OpenCloseIcon = _OpenCloseIcon;
export const OrganizationIcon = _OrganizationIcon;
export const ProjectEventIcon = _ProjectEventIcon;
export const QualifierIcon = _QualifierIcon;
query?: Query;
}
+export function getBaseUrl(): string {
+ return (window as any).baseUrl;
+}
+
/**
* Generate URL for a component's home page
*/
export function getComponentUrl(componentKey: string, branch?: string): string {
const branchQuery = branch ? `&branch=${encodeURIComponent(branch)}` : '';
- return (
- (window as any).baseUrl + '/dashboard?id=' + encodeURIComponent(componentKey) + branchQuery
- );
+ return getBaseUrl() + '/dashboard?id=' + encodeURIComponent(componentKey) + branchQuery;
}
export function getProjectUrl(key: string, branch?: string): Location {
return { pathname: '/dashboard', query: { id: key, branch } };
}
-export function getProjectBranchUrl(key: string, branch: Branch) {
+export function getProjectBranchUrl(key: string, branch: Branch): Location {
if (isShortLivingBranch(branch)) {
return {
pathname: '/project/issues',
export function getComponentIssuesUrlAsString(componentKey: string, query?: Query): string {
const path = getComponentIssuesUrl(componentKey, query);
- return `${(window as any).baseUrl}${path.pathname}?${stringify(path.query)}`;
+ return `${getBaseUrl()}${path.pathname}?${stringify(path.query)}`;
}
/**
* Generate URL for a component's drilldown page
*/
-export function getComponentDrilldownUrl(componentKey: string, metric: string, branch?: string) {
+export function getComponentDrilldownUrl(
+ componentKey: string,
+ metric: string,
+ branch?: string
+): Location {
return { pathname: '/component_measures', query: { id: componentKey, metric, branch } };
}
}
export function getProjectsUrl(): string {
- return (window as any).baseUrl + '/projects';
+ return getBaseUrl() + '/projects';
}
export function getMarkdownHelpUrl(): string {
- return (window as any).baseUrl + '/markdown/help';
+ return getBaseUrl() + '/markdown/help';
}
rename=Rename
reset_verb=Reset
resolution=Resolution
+restart=Restart
restore=Restore
result=Result
results=Results
# SYSTEM
#
#------------------------------------------------------------------------------
+system.application_nodes_title=Application Nodes
+system.are_you_sure_to_restart=Are you sure you want to restart the server?
+system.cluster_log_level.info=Changes apply to all Application nodes but not to Search nodes.
+system.download_logs=Download Logs
+system.download_system_info=Download System Info
+system.is_restarting=Server is restarting. This page will be automatically refreshed.
system.log_level.warning=Current level has performance impacts, please make sure to get back to INFO level once your investigation is done. Please note that when the server is restarted, logging will revert to the level configured in sonar.properties.
-
+system.log_level.info=Changes don't apply to Search.
+system.logs_level=Logs level
+system.restart_server=Restart Server
+system.search_nodes_title=Search Nodes
+system.set_log_level=Set logs level
#------------------------------------------------------------------------------