import org.sonar.ce.cleaning.CeCleaningModule;
import org.sonar.ce.db.ReadOnlyPropertiesDao;
import org.sonar.ce.log.CeProcessLogging;
+import org.sonar.ce.monitoring.CeSystemInfoModule;
import org.sonar.ce.platform.ComputeEngineExtensionInstaller;
import org.sonar.ce.queue.CeQueueCleaner;
import org.sonar.ce.queue.PurgeCeActivities;
container.add(
StartableHazelcastMember.class,
CeDistributedInformationImpl.class);
+ container.add(CeSystemInfoModule.forClusterMode());
} else {
container.add(StandaloneCeDistributedInformation.class);
}
--- /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.ce.monitoring;
+
+import org.sonar.process.systeminfo.JvmPropertiesSection;
+import org.sonar.process.systeminfo.JvmStateSection;
+import org.sonar.server.platform.monitoring.DatabaseSection;
+import org.sonar.server.platform.monitoring.cluster.ProcessInfoProvider;
+
+public class CeSystemInfoModule {
+
+ private CeSystemInfoModule() {
+ // do not instantiate
+ }
+
+ public static Object[] forClusterMode() {
+ return new Object[] {
+ new JvmPropertiesSection("Compute Engine JVM Properties"),
+ new JvmStateSection("Compute Engine JVM State"),
+ DatabaseSection.class,
+ ProcessInfoProvider.class
+ };
+ }
+}
--- /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;
+
+/**
+ * Interface to mark {@link SystemInfoSection} of web server as global.
+ * In case of cluster mode, all the processes and nodes would return
+ * the same values, so it's loaded once on the web server that receives
+ * the user request.
+ */
+public interface Global {
+}
import java.util.Map;
import java.util.Objects;
+import java.util.TreeMap;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder();
protobuf.setName(name);
- for (Map.Entry<Object, Object> systemProp : System.getProperties().entrySet()) {
+ Map<Object, Object> sortedProperties = new TreeMap<>(System.getProperties());
+ for (Map.Entry<Object, Object> systemProp : sortedProperties.entrySet()) {
if (systemProp.getValue() != null) {
setAttribute(protobuf, Objects.toString(systemProp.getKey()), Objects.toString(systemProp.getValue()));
}
ThreadMXBean thread = ManagementFactory.getThreadMXBean();
setAttribute(protobuf, "Threads", thread.getThreadCount());
- setAttribute(protobuf,"Processors", Runtime.getRuntime().availableProcessors());
-
return protobuf.build();
}
*/
package org.sonar.process.systeminfo;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo.Section;
+
+import static java.util.Arrays.stream;
public class SystemInfoUtils {
// prevent instantiation
}
- public static void setAttribute(ProtobufSystemInfo.Section.Builder section, String key, @Nullable String value) {
+ public static void setAttribute(Section.Builder section, String key, @Nullable String value) {
if (value != null) {
section.addAttributesBuilder()
.setKey(key)
}
}
- public static void setAttribute(ProtobufSystemInfo.Section.Builder section, String key, @Nullable Collection<String> values) {
+ public static void setAttribute(Section.Builder section, String key, @Nullable Collection<String> values) {
if (values != null) {
section.addAttributesBuilder()
.setKey(key)
}
}
- public static void setAttribute(ProtobufSystemInfo.Section.Builder section, String key, boolean value) {
+ public static void setAttribute(Section.Builder section, String key, boolean value) {
section.addAttributesBuilder()
.setKey(key)
.setBooleanValue(value)
.build();
}
- public static void setAttribute(ProtobufSystemInfo.Section.Builder section, String key, long value) {
+ public static void setAttribute(Section.Builder section, String key, long value) {
section.addAttributesBuilder()
.setKey(key)
.setLongValue(value)
}
@CheckForNull
- public static ProtobufSystemInfo.Attribute attribute(ProtobufSystemInfo.Section section, String key) {
+ public static ProtobufSystemInfo.Attribute attribute(Section section, String key) {
for (ProtobufSystemInfo.Attribute attribute : section.getAttributesList()) {
if (attribute.getKey().equals(key)) {
return attribute;
}
return null;
}
+
+ public static List<Section> order(Collection<Section> sections, String... orderedNames) {
+ Map<String, Section> alphabeticalOrderedMap = new TreeMap<>();
+ sections.forEach(section -> alphabeticalOrderedMap.put(section.getName(), section));
+
+ List<Section> result = new ArrayList<>(sections.size());
+ stream(orderedNames).forEach(name -> {
+ Section section = alphabeticalOrderedMap.remove(name);
+ if (section != null) {
+ result.add(section);
+ }
+ });
+ result.addAll(alphabeticalOrderedMap.values());
+ return result;
+ }
}
*/
package org.sonar.process.systeminfo;
-import org.assertj.core.api.Assertions;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
import org.junit.Test;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.sonar.process.systeminfo.SystemInfoUtils.attribute;
public class JvmPropertiesSectionTest {
}
@Test
- public void test_toProtobuf() {
+ public void system_properties_are_returned_in_alphabetical_order() {
ProtobufSystemInfo.Section section = underTest.toProtobuf();
- Assertions.assertThat(attribute(section, "java.vm.vendor").getStringValue()).isNotEmpty();
- Assertions.assertThat(attribute(section, "os.name").getStringValue()).isNotEmpty();
+ List<String> keys = section.getAttributesList()
+ .stream()
+ .map(ProtobufSystemInfo.Attribute::getKey)
+ .collect(Collectors.toList());
+ assertThat(keys).contains("java.vm.vendor", "os.name");
+
+ List<String> sortedKeys = new ArrayList<>(keys);
+ Collections.sort(sortedKeys);
+ assertThat(sortedKeys).isEqualTo(keys);
}
}
assertThat(section.getName()).isEqualTo(PROCESS_NAME);
assertThat(section.getAttributesCount()).isGreaterThan(0);
- assertThat(section.getAttributesList()).extracting("key").contains("Threads", "Processors");
+ assertThat(section.getAttributesList()).extracting("key").contains("Threads", "Heap Max (MB)");
}
@Test
--- /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.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo.Section;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class SystemInfoUtilsTest {
+
+ @Test
+ public void test_order() {
+ Collection<Section> sections = asList(
+ newSection("end2"),
+ newSection("bar"),
+ newSection("end1"),
+ newSection("foo"));
+
+ List<String> ordered = SystemInfoUtils.order(sections, "foo", "bar").stream()
+ .map(Section::getName)
+ .collect(Collectors.toList());
+ assertThat(ordered).isEqualTo(asList("foo", "bar", "end1", "end2"));
+ }
+
+ private static Section newSection(String name) {
+ return Section.newBuilder().setName(name).build();
+ }
+}
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.admin.indices.stats.IndexStats;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
+import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.log.Loggers;
+import org.sonar.process.systeminfo.Global;
import org.sonar.process.systeminfo.SystemInfoSection;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import org.sonar.server.es.EsClient;
import static org.apache.commons.io.FileUtils.byteCountToDisplaySize;
import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
-public class EsStatisticsSection implements SystemInfoSection {
+@ServerSide
+public class EsStatisticsSection implements SystemInfoSection, Global {
private final EsClient esClient;
--- /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 org.sonar.api.platform.Server;
+import org.sonar.api.server.ServerSide;
+
+@ServerSide
+public class OfficialDistribution {
+ static final String BRANDING_FILE_PATH = "web/WEB-INF/classes/com/sonarsource/branding";
+
+ private final Server server;
+
+ public OfficialDistribution(Server server) {
+ this.server = server;
+ }
+
+ public boolean check() {
+ // the dependency com.sonarsource:sonarsource-branding is shaded to webapp
+ // during release (see sonar-web pom)
+ File brandingFile = new File(server.getRootDir(), BRANDING_FILE_PATH);
+ // no need to check that the file exists. java.io.File#length() returns zero in this case.
+ return brandingFile.length() > 0L;
+ }
+}
*/
package org.sonar.server.platform.monitoring;
+import org.sonar.api.server.ServerSide;
import org.sonar.core.platform.PluginInfo;
import org.sonar.core.platform.PluginRepository;
import org.sonar.process.systeminfo.SystemInfoSection;
import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
+@ServerSide
public class PluginsSection implements SystemInfoSection {
private final PluginRepository repository;
import org.sonar.api.config.PropertyDefinition;
import org.sonar.api.config.PropertyDefinitions;
import org.sonar.api.config.Settings;
+import org.sonar.api.server.ServerSide;
+import org.sonar.process.systeminfo.Global;
import org.sonar.process.systeminfo.SystemInfoSection;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import static org.apache.commons.lang.StringUtils.abbreviate;
import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
-public class SettingsSection implements SystemInfoSection {
+@ServerSide
+public class SettingsSection implements SystemInfoSection, Global {
static final int MAX_VALUE_LENGTH = 500;
private final Settings settings;
--- /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.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.health.Health;
+import org.sonar.server.health.HealthChecker;
+import org.sonar.server.platform.ServerIdLoader;
+import org.sonar.server.platform.ServerLogging;
+import org.sonar.server.user.SecurityRealmFactory;
+
+import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
+
+public class StandaloneSystemSection extends BaseSectionMBean implements SystemSectionMBean {
+
+ private static final Joiner COMMA_JOINER = Joiner.on(", ");
+
+ private final Configuration config;
+ private final SecurityRealmFactory securityRealmFactory;
+ private final IdentityProviderRepository identityProviderRepository;
+ private final Server server;
+ private final ServerLogging serverLogging;
+ private final ServerIdLoader serverIdLoader;
+ private final OfficialDistribution officialDistribution;
+ private final HealthChecker healthChecker;
+
+ public StandaloneSystemSection(Configuration config, SecurityRealmFactory securityRealmFactory,
+ IdentityProviderRepository identityProviderRepository, Server server, ServerLogging serverLogging,
+ ServerIdLoader serverIdLoader, OfficialDistribution officialDistribution, HealthChecker healthChecker) {
+ this.config = config;
+ this.securityRealmFactory = securityRealmFactory;
+ this.identityProviderRepository = identityProviderRepository;
+ this.server = server;
+ this.serverLogging = serverLogging;
+ this.serverIdLoader = serverIdLoader;
+ this.officialDistribution = officialDistribution;
+ this.healthChecker = healthChecker;
+ }
+
+ @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);
+ }
+
+ @Override
+ public String name() {
+ // JMX name
+ return "SonarQube";
+ }
+
+ @Override
+ public ProtobufSystemInfo.Section toProtobuf() {
+ ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder();
+ protobuf.setName("System");
+
+ serverIdLoader.get().ifPresent(serverId -> {
+ setAttribute(protobuf, "Server ID", serverId.getId());
+ setAttribute(protobuf, "Server ID validated", serverId.isValid());
+ });
+ Health health = healthChecker.checkNode();
+ setAttribute(protobuf, "Health", health.getStatus().name());
+ setAttribute(protobuf, "Health Causes", health.getCauses());
+ setAttribute(protobuf, "Version", getVersion());
+ setAttribute(protobuf, "External User Authentication", getExternalUserAuthentication());
+ addIfNotEmpty(protobuf, "Accepted external identity providers", getEnabledIdentityProviders());
+ addIfNotEmpty(protobuf, "External identity providers whose users are allowed to sign themselves up", getAllowsToSignUpEnabledIdentityProviders());
+ setAttribute(protobuf, "High Availability", false);
+ setAttribute(protobuf, "Official Distribution", officialDistribution.check());
+ setAttribute(protobuf, "Force authentication", getForceAuthentication());
+ setAttribute(protobuf, "Home Dir", config.get(ProcessProperties.PATH_HOME).orElse(null));
+ setAttribute(protobuf, "Data Dir", config.get(ProcessProperties.PATH_DATA).orElse(null));
+ setAttribute(protobuf, "Temp Dir", config.get(ProcessProperties.PATH_TEMP).orElse(null));
+ setAttribute(protobuf, "Logs Dir", config.get(ProcessProperties.PATH_LOGS).orElse(null));
+ setAttribute(protobuf, "Logs Level", getLogLevel());
+ setAttribute(protobuf, "Processors", Runtime.getRuntime().availableProcessors());
+ return protobuf.build();
+ }
+
+ 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 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.health.Health;
-import org.sonar.server.health.HealthChecker;
-import org.sonar.server.platform.ServerIdLoader;
-import org.sonar.server.platform.ServerLogging;
-import org.sonar.server.user.SecurityRealmFactory;
-
-import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
-
-public class SystemSection extends BaseSectionMBean implements SystemSectionMBean {
-
- private static final Joiner COMMA_JOINER = Joiner.on(", ");
-
- static final String BRANDING_FILE_PATH = "web/WEB-INF/classes/com/sonarsource/branding";
-
- private final Configuration config;
- private final SecurityRealmFactory securityRealmFactory;
- private final IdentityProviderRepository identityProviderRepository;
- private final Server server;
- private final ServerLogging serverLogging;
- private final ServerIdLoader serverIdLoader;
- private final HealthChecker healthChecker;
-
- public SystemSection(Configuration config, SecurityRealmFactory securityRealmFactory,
- IdentityProviderRepository identityProviderRepository, Server server, ServerLogging serverLogging,
- ServerIdLoader serverIdLoader, HealthChecker healthChecker) {
- this.config = config;
- this.securityRealmFactory = securityRealmFactory;
- this.identityProviderRepository = identityProviderRepository;
- this.server = server;
- this.serverLogging = serverLogging;
- this.serverIdLoader = serverIdLoader;
- this.healthChecker = healthChecker;
- }
-
- @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() {
- // JMX name
- return "SonarQube";
- }
-
- @Override
- public ProtobufSystemInfo.Section toProtobuf() {
- ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder();
- protobuf.setName("System");
-
- serverIdLoader.get().ifPresent(serverId -> {
- setAttribute(protobuf, "Server ID", serverId.getId());
- setAttribute(protobuf, "Server ID validated", serverId.isValid());
- });
- Health health = healthChecker.checkNode();
- setAttribute(protobuf, "Health", health.getStatus().name());
- setAttribute(protobuf, "Health Causes", health.getCauses());
- setAttribute(protobuf, "Version", getVersion());
- setAttribute(protobuf, "External User Authentication", getExternalUserAuthentication());
- addIfNotEmpty(protobuf, "Accepted external identity providers", getEnabledIdentityProviders());
- addIfNotEmpty(protobuf, "External identity providers whose users are allowed to sign themselves up", getAllowsToSignUpEnabledIdentityProviders());
- setAttribute(protobuf, "High Availability", false);
- setAttribute(protobuf, "Official Distribution", isOfficialDistribution());
- setAttribute(protobuf, "Force authentication", getForceAuthentication());
- setAttribute(protobuf, "Home Dir", config.get(ProcessProperties.PATH_HOME).orElse(null));
- setAttribute(protobuf, "Data Dir", config.get(ProcessProperties.PATH_DATA).orElse(null));
- setAttribute(protobuf, "Temp Dir", config.get(ProcessProperties.PATH_TEMP).orElse(null));
- setAttribute(protobuf, "Logs Dir", config.get(ProcessProperties.PATH_LOGS).orElse(null));
- setAttribute(protobuf, "Logs Level", getLogLevel());
- 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));
- }
- }
-}
import org.sonar.process.systeminfo.JvmPropertiesSection;
import org.sonar.process.systeminfo.JvmStateSection;
+import org.sonar.server.platform.monitoring.cluster.AppNodesInfoLoaderImpl;
+import org.sonar.server.platform.monitoring.cluster.GlobalInfoLoader;
+import org.sonar.server.platform.monitoring.cluster.GlobalSystemSection;
+import org.sonar.server.platform.monitoring.cluster.ProcessInfoProvider;
+import org.sonar.server.platform.monitoring.cluster.NodeSystemSection;
import org.sonar.server.platform.ws.ClusterInfoAction;
import org.sonar.server.platform.ws.StandaloneInfoAction;
EsStatisticsSection.class,
PluginsSection.class,
SettingsSection.class,
- SystemSection.class,
+ StandaloneSystemSection.class,
+
+ OfficialDistribution.class,
StandaloneInfoAction.class
};
new JvmPropertiesSection("Web JVM Properties"),
new JvmStateSection("Web JVM State"),
DatabaseSection.class,
- EsStateSection.class,
+ EsStatisticsSection.class,
+ GlobalSystemSection.class,
+ NodeSystemSection.class,
PluginsSection.class,
+ SettingsSection.class,
+
+ OfficialDistribution.class,
+ ProcessInfoProvider.class,
+ GlobalInfoLoader.class,
+ AppNodesInfoLoaderImpl.class,
ClusterInfoAction.class
};
}
--- /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.cluster;
+
+import java.util.Collection;
+
+public interface AppNodesInfoLoader {
+
+ Collection<NodeInfo> load();
+}
--- /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.cluster;
+
+import com.hazelcast.core.Member;
+import com.hazelcast.core.MemberSelector;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import org.sonar.api.server.ServerSide;
+import org.sonar.process.ProcessId;
+import org.sonar.process.cluster.hz.DistributedAnswer;
+import org.sonar.process.cluster.hz.HazelcastMember;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+@ServerSide
+public class AppNodesInfoLoaderImpl implements AppNodesInfoLoader {
+
+ private final HazelcastMember hzMember;
+
+ public AppNodesInfoLoaderImpl(HazelcastMember hzMember) {
+ this.hzMember = hzMember;
+ }
+
+ public Collection<NodeInfo> load() {
+ try {
+ Map<String, NodeInfo> nodesByName = new HashMap<>();
+ DistributedAnswer<ProtobufSystemInfo.SystemInfo> distributedAnswer = hzMember.call(ProcessInfoProvider::provide, new CeWebMemberSelector(), 15_000L);
+ for (Member member : distributedAnswer.getMembers()) {
+ String nodeName = member.getStringAttribute(HazelcastMember.Attribute.NODE_NAME);
+ NodeInfo nodeInfo = nodesByName.get(nodeName);
+ if (nodeInfo == null) {
+ nodeInfo = new NodeInfo(nodeName);
+ nodesByName.put(nodeName, nodeInfo);
+
+ String hostname = member.getStringAttribute(HazelcastMember.Attribute.HOSTNAME);
+ nodeInfo.setAttribute("Hostname", hostname);
+ }
+ completeNodeInfo(distributedAnswer, member, nodeInfo);
+ }
+ return nodesByName.values();
+
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private void completeNodeInfo(DistributedAnswer<ProtobufSystemInfo.SystemInfo> distributedAnswer, Member member, NodeInfo nodeInfo) {
+ Optional<ProtobufSystemInfo.SystemInfo> nodeAnswer = distributedAnswer.getAnswer(member);
+ Optional<Exception> failure = distributedAnswer.getFailed(member);
+ if (distributedAnswer.hasTimedOut(member)) {
+ nodeInfo.setAttribute("Error", "Failed to retrieve information on time");
+ } else if (failure.isPresent()) {
+ nodeInfo.setAttribute("Error", "Failed to retrieve information: " + failure.get().getMessage());
+ } else if (nodeAnswer.isPresent()) {
+ nodeAnswer.get().getSectionsList().forEach(nodeInfo::addSection);
+ }
+ }
+
+ private static class CeWebMemberSelector implements MemberSelector {
+ @Override
+ public boolean select(Member member) {
+ String processKey = member.getStringAttribute(HazelcastMember.Attribute.PROCESS_KEY);
+ return processKey.equals(ProcessId.WEB_SERVER.getKey()) || processKey.equals(ProcessId.COMPUTE_ENGINE.getKey());
+ }
+ }
+}
--- /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.cluster;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.sonar.api.server.ServerSide;
+import org.sonar.process.systeminfo.Global;
+import org.sonar.process.systeminfo.SystemInfoSection;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+@ServerSide
+public class GlobalInfoLoader {
+ private final List<SystemInfoSection> globalSections;
+
+ public GlobalInfoLoader(SystemInfoSection[] sections) {
+ this.globalSections = Arrays.stream(sections)
+ .filter(section -> section instanceof Global)
+ .collect(Collectors.toList());
+ }
+
+ public List<ProtobufSystemInfo.Section> load() {
+ return globalSections.stream()
+ .map(SystemInfoSection::toProtobuf)
+ .collect(Collectors.toList());
+ }
+}
--- /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.cluster;
+
+import com.google.common.base.Joiner;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.CoreProperties;
+import org.sonar.api.config.Configuration;
+import org.sonar.api.security.SecurityRealm;
+import org.sonar.api.server.ServerSide;
+import org.sonar.api.server.authentication.IdentityProvider;
+import org.sonar.core.util.stream.MoreCollectors;
+import org.sonar.process.systeminfo.Global;
+import org.sonar.process.systeminfo.SystemInfoSection;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.server.authentication.IdentityProviderRepository;
+import org.sonar.server.health.ClusterHealth;
+import org.sonar.server.health.HealthChecker;
+import org.sonar.server.platform.ServerIdLoader;
+import org.sonar.server.user.SecurityRealmFactory;
+
+import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
+
+@ServerSide
+public class GlobalSystemSection implements SystemInfoSection, Global {
+ private static final Joiner COMMA_JOINER = Joiner.on(", ");
+
+ private final Configuration config;
+ private final ServerIdLoader serverIdLoader;
+ private final SecurityRealmFactory securityRealmFactory;
+ private final IdentityProviderRepository identityProviderRepository;
+ private final HealthChecker healthChecker;
+
+ public GlobalSystemSection(Configuration config, ServerIdLoader serverIdLoader, SecurityRealmFactory securityRealmFactory,
+ IdentityProviderRepository identityProviderRepository, HealthChecker healthChecker) {
+ this.config = config;
+ this.serverIdLoader = serverIdLoader;
+ this.securityRealmFactory = securityRealmFactory;
+ this.identityProviderRepository = identityProviderRepository;
+ this.healthChecker = healthChecker;
+ }
+
+ @Override
+ public ProtobufSystemInfo.Section toProtobuf() {
+ ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder();
+ protobuf.setName("System");
+
+ ClusterHealth health = healthChecker.checkCluster();
+
+ setAttribute(protobuf, "Health", health.getHealth().getStatus().name());
+ setAttribute(protobuf, "Health Causes", health.getHealth().getCauses());
+ serverIdLoader.get().ifPresent(serverId -> {
+ setAttribute(protobuf, "Server ID", serverId.getId());
+ setAttribute(protobuf, "Server ID validated", serverId.isValid());
+ });
+ setAttribute(protobuf, "High Availability", true);
+ setAttribute(protobuf, "External User Authentication", getExternalUserAuthentication());
+ addIfNotEmpty(protobuf, "Accepted external identity providers", getEnabledIdentityProviders());
+ addIfNotEmpty(protobuf, "External identity providers whose users are allowed to sign themselves up", getAllowsToSignUpEnabledIdentityProviders());
+ setAttribute(protobuf, "Force authentication", getForceAuthentication());
+ return protobuf.build();
+ }
+
+ private List<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 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));
+ }
+ }
+
+ @CheckForNull
+ private String getExternalUserAuthentication() {
+ SecurityRealm realm = securityRealmFactory.getRealm();
+ return realm == null ? null : realm.getName();
+ }
+
+}
--- /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.cluster;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+public class NodeInfo {
+
+ private final String name;
+ private final Map<String, String> attributes = new LinkedHashMap<>();
+ private final List<ProtobufSystemInfo.Section> sections = new ArrayList<>();
+
+ public NodeInfo(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public NodeInfo setAttribute(String key, String value) {
+ this.attributes.put(key, value);
+ return this;
+ }
+
+ public Map<String, String> getAttributes() {
+ return attributes;
+ }
+
+ public NodeInfo addSection(ProtobufSystemInfo.Section section) {
+ this.sections.add(section);
+ return this;
+ }
+
+ public List<ProtobufSystemInfo.Section> getSections() {
+ return sections;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ NodeInfo nodeInfo = (NodeInfo) o;
+ return name.equals(nodeInfo.name);
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+}
--- /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.cluster;
+
+import org.sonar.api.config.Configuration;
+import org.sonar.api.platform.Server;
+import org.sonar.api.server.ServerSide;
+import org.sonar.process.ProcessProperties;
+import org.sonar.process.systeminfo.SystemInfoSection;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.server.health.Health;
+import org.sonar.server.health.HealthChecker;
+import org.sonar.server.platform.ServerLogging;
+import org.sonar.server.platform.monitoring.OfficialDistribution;
+
+import static org.sonar.process.systeminfo.SystemInfoUtils.setAttribute;
+
+@ServerSide
+public class NodeSystemSection implements SystemInfoSection {
+
+ private final Configuration config;
+ private final Server server;
+ private final ServerLogging serverLogging;
+ private final OfficialDistribution officialDistribution;
+ private final HealthChecker healthChecker;
+
+ public NodeSystemSection(Configuration config, Server server, ServerLogging serverLogging,
+ OfficialDistribution officialDistribution, HealthChecker healthChecker) {
+ this.config = config;
+ this.server = server;
+ this.serverLogging = serverLogging;
+ this.officialDistribution = officialDistribution;
+ this.healthChecker = healthChecker;
+ }
+
+ @Override
+ public ProtobufSystemInfo.Section toProtobuf() {
+ ProtobufSystemInfo.Section.Builder protobuf = ProtobufSystemInfo.Section.newBuilder();
+ protobuf.setName("System");
+
+ Health health = healthChecker.checkNode();
+ setAttribute(protobuf, "Health", health.getStatus().name());
+ setAttribute(protobuf, "Health Causes", health.getCauses());
+ setAttribute(protobuf, "Version", server.getVersion());
+ setAttribute(protobuf, "Official Distribution", officialDistribution.check());
+ setAttribute(protobuf, "Home Dir", config.get(ProcessProperties.PATH_HOME).orElse(null));
+ setAttribute(protobuf, "Data Dir", config.get(ProcessProperties.PATH_DATA).orElse(null));
+ setAttribute(protobuf, "Temp Dir", config.get(ProcessProperties.PATH_TEMP).orElse(null));
+ setAttribute(protobuf, "Logs Dir", config.get(ProcessProperties.PATH_LOGS).orElse(null));
+ setAttribute(protobuf, "Logs Level", serverLogging.getRootLoggerLevel().name());
+ return protobuf.build();
+ }
+
+}
--- /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.cluster;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.sonar.api.Startable;
+import org.sonar.api.ce.ComputeEngineSide;
+import org.sonar.api.server.ServerSide;
+import org.sonar.process.systeminfo.Global;
+import org.sonar.process.systeminfo.SystemInfoSection;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+
+@ServerSide
+@ComputeEngineSide
+public class ProcessInfoProvider implements Startable {
+
+ /** Used for Hazelcast's distributed queries in cluster mode */
+ private static ProcessInfoProvider INSTANCE;
+ private final List<SystemInfoSection> sections;
+
+ public ProcessInfoProvider(SystemInfoSection[] sections) {
+ this.sections = Arrays.stream(sections)
+ .filter(section -> !(section instanceof Global))
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public void start() {
+ INSTANCE = this;
+ }
+
+ @Override
+ public void stop() {
+ INSTANCE = null;
+ }
+
+ public static ProtobufSystemInfo.SystemInfo provide() {
+ ProtobufSystemInfo.SystemInfo.Builder protobuf = ProtobufSystemInfo.SystemInfo.newBuilder();
+ INSTANCE.sections.forEach(section -> protobuf.addSections(section.toProtobuf()));
+ return protobuf.build();
+ }
+}
--- /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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.server.platform.monitoring.cluster;
+
+import javax.annotation.ParametersAreNonnullByDefault;
*/
package org.sonar.server.platform.ws;
-import java.util.Arrays;
+import java.util.Collection;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.text.JsonWriter;
+import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
+import org.sonar.server.platform.monitoring.cluster.AppNodesInfoLoader;
+import org.sonar.server.platform.monitoring.cluster.GlobalInfoLoader;
+import org.sonar.server.platform.monitoring.cluster.NodeInfo;
import org.sonar.server.user.UserSession;
public class ClusterInfoAction implements SystemWsAction {
private final UserSession userSession;
+ private final GlobalInfoLoader globalInfoLoader;
+ private final AppNodesInfoLoader appNodesInfoLoader;
- public ClusterInfoAction(UserSession userSession) {
+ public ClusterInfoAction(UserSession userSession, GlobalInfoLoader globalInfoLoader, AppNodesInfoLoader appNodesInfoLoader) {
this.userSession = userSession;
+ this.globalInfoLoader = globalInfoLoader;
+ this.appNodesInfoLoader = appNodesInfoLoader;
}
@Override
try (JsonWriter json = response.newJsonWriter()) {
json.beginObject();
-
- json.name("System");
- json.beginObject();
- json.prop("High Availability", true);
- json.prop("Cluster Name", "fooo");
- json.prop("Server Id", "ABC123");
- json.prop("Health", "RED");
- json
- .name("Health Causes")
- .beginArray().values(Arrays.asList("foo", "bar")).endArray();
- json.endObject();
-
- json.name("Settings");
- json.beginObject();
- json.prop("sonar.forceAuthentication", true);
- json.prop("sonar.externalIdentityProviders", "GitHub, BitBucket");
+ writeGlobal(json);
+ writeApplicationNodes(json);
json.endObject();
+ }
- json.name("Database");
- json
- .beginObject()
- .prop("Name", "PostgreSQL")
- .prop("Version", "9.6.3")
- .endObject();
-
- json.name("Compute Engine");
- json
- .beginObject()
- .prop("Pending", 5)
- .prop("In Progress", 4)
- .prop("workers", 8)
- .prop("workersPerNode", 4)
- .endObject();
-
- json.name("Search");
- json
- .beginObject()
- .prop("Health", "GREEN")
- .prop("Number of Nodes", 4)
- .prop("Index Components - Docs", 152_515_155)
- .prop("Index Components - Shards", 20)
- .prop("Index Components - Size", "25GB")
- .prop("Index Issues - Docs", 5)
- .prop("Index Issues - Shards", 5)
- .prop("Index Issues - Size", "52MB")
- .prop("Index Tests - Docs", 56605)
- .prop("Index Tests - Shards", 2)
- .prop("Index Tests - Size", "520MB")
- .endObject();
-
- json.name("Application Nodes");
- json
- .beginArray()
- .beginObject()
- .prop("Name", "Mont Blanc")
- .prop("Host", "10.158.92.16")
- .prop("Health", "YELLOW")
- .name("healthCauses").beginArray().beginObject().prop("message", "Db connectivity error").endObject().endArray()
- .prop("Start Time", "2017-05-30T10:23:45")
- .prop("Official Distribution", true)
- .prop("Processors", 4);
- json
- .name("Web JVM").beginObject()
- .prop("JVM Name", "Java HotSpot(TM) 64-Bit Server VM")
- .prop("JVM Vendor", "Oracle Corporation")
- .prop("Max Memory", "948MB")
- .prop("Free Memory", "38MB")
- .endObject()
-
- .name("Web JVM Properties").beginObject()
- .prop("catalina.home", "/sonarsource/var/tmp/sonarsource/sssonarqube/tc")
- .prop("glowroot.tmp.dir", "/var/tmp/sonarsource/ssglowroot-agent")
- .prop("glowroot.adad.dir", "/var/tmp/sonarsource/ssglowroot-agent")
- .prop("java.specification.version", "1.8")
- .endObject()
-
- .name("Web Database Connectivity").beginObject()
- .prop("Driver", "PostgreSQL JDBC Driver")
- .prop("Driver Version", "PostgreSQL JDBC Driver")
- .prop("Pool Idle Connections", 2)
- .prop("Pool Max Connections", 50)
- .prop("URL", "jdbc:postgresql://next-rds.cn6pfc2xc6oq.us-east-1.rds.amazonaws.com/dory")
- .endObject();
-
- json
- .name("Compute Engine JVM").beginObject()
- .prop("JVM Name", "Java HotSpot(TM) 64-Bit Server VM")
- .prop("JVM Vendor", "Oracle Corporation")
- .prop("Max Memory", "25MB")
- .prop("Free Memory", "8MB")
- .endObject();
-
- json
- .name("Compute Engine JVM Properties").beginObject()
- .prop("java.ext.dirs", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
- .prop("java.io.tmpdir", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
- .prop("java.library.path", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
- .prop("java.net.preferIPv4Stack", true)
- .prop("java.rmi.server.randomIDs", true)
- .prop("java.specification.version", "1.8")
- .endObject();
+// try (JsonWriter json = response.newJsonWriter()) {
+// json.beginObject();
+//
+// // global section
+// json.prop("Cluster", true);
+// json.prop("Cluster Name", "foo");
+// json.prop("Server Id", "ABC123");
+// json.prop("Health", "RED");
+// json
+// .name("Health Causes")
+// .beginArray().beginObject().prop("message", "Requires at least two search nodes").endObject().endArray();
+//
+// json.name("Settings");
+// json.beginObject();
+// json.prop("sonar.forceAuthentication", true);
+// json.prop("sonar.externalIdentityProviders", "GitHub, BitBucket");
+// json.endObject();
+//
+// json.name("Database");
+// json
+// .beginObject()
+// .prop("Name", "PostgreSQL")
+// .prop("Version", "9.6.3")
+// .endObject();
+//
+// json.name("Compute Engine");
+// json
+// .beginObject()
+// .prop("Pending", 5)
+// .prop("In Progress", 4)
+// .prop("workers", 8)
+// .prop("workersPerNode", 4)
+// .endObject();
+//
+// json.name("Elasticsearch");
+// json
+// .beginObject()
+// .prop("Health", "GREEN")
+// .prop("Number of Nodes", 4)
+// .prop("Index Components - Docs", 152_515_155)
+// .prop("Index Components - Shards", 20)
+// .prop("Index Components - Size", "25GB")
+// .prop("Index Issues - Docs", 5)
+// .prop("Index Issues - Shards", 5)
+// .prop("Index Issues - Size", "52MB")
+// .prop("Index Tests - Docs", 56605)
+// .prop("Index Tests - Shards", 2)
+// .prop("Index Tests - Size", "520MB")
+// .endObject();
+//
+// json.name("Application Nodes");
+// json
+// .beginArray()
+// .beginObject()
+// .prop("Name", "Mont Blanc")
+// .prop("Host", "10.158.92.16")
+// .prop("Health", "YELLOW")
+// .name("healthCauses").beginArray().beginObject().prop("message", "Db connectivity error").endObject().endArray()
+// .prop("Start Time", "2017-05-30T10:23:45")
+// .prop("Official Distribution", true)
+// .prop("Processors", 4);
+// json
+// .name("Web JVM").beginObject()
+// .prop("JVM Name", "Java HotSpot(TM) 64-Bit Server VM")
+// .prop("JVM Vendor", "Oracle Corporation")
+// .prop("Max Memory", "948MB")
+// .prop("Free Memory", "38MB")
+// .endObject()
+//
+// .name("Web JVM Properties").beginObject()
+// .prop("catalina.home", "/sonarsource/var/tmp/sonarsource/sssonarqube/tc")
+// .prop("glowroot.tmp.dir", "/var/tmp/sonarsource/ssglowroot-agent")
+// .prop("glowroot.adad.dir", "/var/tmp/sonarsource/ssglowroot-agent")
+// .prop("java.specification.version", "1.8")
+// .endObject()
+//
+// .name("Web Database Connectivity").beginObject()
+// .prop("Driver", "PostgreSQL JDBC Driver")
+// .prop("Driver Version", "PostgreSQL JDBC Driver")
+// .prop("Pool Idle Connections", 2)
+// .prop("Pool Max Connections", 50)
+// .prop("URL", "jdbc:postgresql://next-rds.cn6pfc2xc6oq.us-east-1.rds.amazonaws.com/dory")
+// .endObject();
+//
+// json
+// .name("Compute Engine JVM").beginObject()
+// .prop("JVM Name", "Java HotSpot(TM) 64-Bit Server VM")
+// .prop("JVM Vendor", "Oracle Corporation")
+// .prop("Max Memory", "25MB")
+// .prop("Free Memory", "8MB")
+// .endObject();
+//
+// json
+// .name("Compute Engine JVM Properties").beginObject()
+// .prop("java.ext.dirs", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
+// .prop("java.io.tmpdir", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
+// .prop("java.library.path", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
+// .prop("java.net.preferIPv4Stack", true)
+// .prop("java.rmi.server.randomIDs", true)
+// .prop("java.specification.version", "1.8")
+// .endObject();
+//
+// json.endObject().endArray();
+//
+// json.name("Search Nodes");
+// json
+// .beginArray()
+// .beginObject()
+// .prop("Name", "Parmelan")
+// .prop("Host", "10.158.92.19")
+// .prop("Health", "GREEN")
+// .name("Health Causes").beginArray().endArray()
+// .prop("Start Time", "2017-05-30T10:23:45")
+// .prop("Processors", 2)
+// .prop("Disk Available", "25GB")
+// .prop("JVM Threads", 52)
+//
+// .name("JVM Properties").beginObject()
+// .prop("java.ext.dirs", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
+// .prop("java.io.tmpdir", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
+// .prop("java.library.path", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
+// .prop("java.net.preferIPv4Stack", true)
+// .prop("java.rmi.server.randomIDs", true)
+// .endObject()
+//
+// .name("JVM").beginObject()
+// .prop("java.ext.dirs", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
+// .prop("java.io.tmpdir", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
+// .prop("java.library.path", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
+// .prop("java.net.preferIPv4Stack", true)
+// .prop("java.rmi.server.randomIDs", true)
+// .endObject()
+//
+// .endObject()
+// .endArray();
+//
+// json.endObject();
+// }
+ }
- json.endObject().endArray();
+ private void writeGlobal(JsonWriter json) {
+ globalInfoLoader.load().forEach(section -> sectionToJson(section, json));
+ }
- json.name("Search Nodes");
- json
- .beginArray()
- .beginObject()
- .prop("Name", "Parmelan")
- .prop("Host", "10.158.92.19")
- .prop("Health", "GREEN")
- .name("Health Causes").beginArray().endArray()
- .prop("Start Time", "2017-05-30T10:23:45")
- .prop("Processors", 2)
- .prop("Disk Available", "25GB")
- .prop("JVM Threads", 52)
+ private void writeApplicationNodes(JsonWriter json) {
+ json.name("Application Nodes").beginArray();
- .name("JVM Properties").beginObject()
- .prop("java.ext.dirs", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
- .prop("java.io.tmpdir", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
- .prop("java.library.path", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
- .prop("java.net.preferIPv4Stack", true)
- .prop("java.rmi.server.randomIDs", true)
- .endObject()
+ Collection<NodeInfo> appNodes = appNodesInfoLoader.load();
+ for (NodeInfo applicationNode : appNodes) {
+ writeApplicationNode(json, applicationNode);
+ }
+ json.endArray();
+ }
- .name("JVM").beginObject()
- .prop("java.ext.dirs", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
- .prop("java.io.tmpdir", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
- .prop("java.library.path", "/opt/sonarsource/jvm/java-1.8.0-sun-x64/jre/lib/ext:/usr/java/packages/lib/ext")
- .prop("java.net.preferIPv4Stack", true)
- .prop("java.rmi.server.randomIDs", true)
- .endObject()
+ private void writeApplicationNode(JsonWriter json, NodeInfo applicationNode) {
+ json.beginObject();
+ json.prop("Name", applicationNode.getName());
+ applicationNode.getSections().forEach(section -> sectionToJson(section, json));
+ json.endObject();
+ }
- .endObject()
- .endArray();
+ private static void sectionToJson(ProtobufSystemInfo.Section section, JsonWriter json) {
+ json.name(section.getName());
+ json.beginObject();
+ for (ProtobufSystemInfo.Attribute attribute : section.getAttributesList()) {
+ attributeToJson(json, attribute);
+ }
+ json.endObject();
+ }
- json.endObject();
+ private static void attributeToJson(JsonWriter json, ProtobufSystemInfo.Attribute attribute) {
+ switch (attribute.getValueCase()) {
+ case BOOLEAN_VALUE:
+ json.prop(attribute.getKey(), attribute.getBooleanValue());
+ break;
+ case LONG_VALUE:
+ json.prop(attribute.getKey(), attribute.getLongValue());
+ break;
+ case DOUBLE_VALUE:
+ json.prop(attribute.getKey(), attribute.getDoubleValue());
+ break;
+ case STRING_VALUE:
+ json.prop(attribute.getKey(), attribute.getStringValue());
+ break;
+ case VALUE_NOT_SET:
+ json.name(attribute.getKey()).beginArray().values(attribute.getStringValuesList()).endArray();
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported type: " + attribute.getValueCase());
}
}
}
*/
package org.sonar.server.platform.ws;
-import java.util.Arrays;
-import java.util.Optional;
+import java.util.List;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.ce.http.CeHttpClient;
+import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.process.systeminfo.SystemInfoSection;
+import org.sonar.process.systeminfo.SystemInfoUtils;
import org.sonar.process.systeminfo.protobuf.ProtobufSystemInfo;
import org.sonar.server.telemetry.TelemetryDataLoader;
import org.sonar.server.user.UserSession;
+import static java.util.Arrays.stream;
import static org.sonar.server.telemetry.TelemetryDataJsonWriter.writeTelemetryData;
/**
*/
public class InfoAction implements SystemWsAction {
+ private static final String[] ORDERED_SECTION_NAMES = {
+ "System", "Database", "Web JVM Properties", "Web JVM State", "Search State", "Search Statistics",
+ "Compute Engine Database Connection", "Compute Engine JVM State", "Compute Engine Tasks"};
private final UserSession userSession;
private final CeHttpClient ceHttpClient;
private final SystemInfoSection[] systemInfoSections;
private void writeJson(JsonWriter json) {
json.beginObject();
- Arrays.stream(systemInfoSections)
+
+ List<ProtobufSystemInfo.Section> sections = stream(systemInfoSections)
.map(SystemInfoSection::toProtobuf)
+ .collect(MoreCollectors.toArrayList());
+ ceHttpClient.retrieveSystemInfo()
+ .ifPresent(ce -> sections.addAll(ce.getSectionsList()));
+ SystemInfoUtils
+ .order(sections, ORDERED_SECTION_NAMES)
.forEach(section -> sectionToJson(section, json));
- Optional<ProtobufSystemInfo.SystemInfo> ceSysInfo = ceHttpClient.retrieveSystemInfo();
- if (ceSysInfo.isPresent()) {
- ceSysInfo.get().getSectionsList().forEach(section -> sectionToJson(section, json));
- }
+
writeStatistics(json);
+
json.endObject();
}
+++ /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.sonar.core.platform.Module;
-import org.sonar.server.telemetry.TelemetryDataLoader;
-
-public class InfoActionModule extends Module {
- @Override
- protected void configureModule() {
- add(TelemetryDataLoader.class,
- InfoAction.class,
- ClusterInfoAction.class,
- StandaloneInfoAction.class);
- }
-}
+++ /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.sonar.core.platform.Module;
-
-public class TelemetryModule extends Module {
- @Override
- protected void configureModule() {
- add(TelemetryDaemon.class,
- TelemetryClient.class);
- }
-}
--- /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 org.apache.commons.io.FileUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.platform.Server;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+
+public class OfficialDistributionTest {
+
+ @Rule
+ public TemporaryFolder temp = new TemporaryFolder();
+
+ private Server server = mock(Server.class);
+ private OfficialDistribution underTest = new OfficialDistribution(server);
+
+ @Test
+ public void official_distribution() throws Exception {
+ File rootDir = temp.newFolder();
+ FileUtils.write(new File(rootDir, OfficialDistribution.BRANDING_FILE_PATH), "1.2");
+ when(server.getRootDir()).thenReturn(rootDir);
+
+ assertThat(underTest.check()).isTrue();
+ }
+
+ @Test
+ public void not_an_official_distribution() throws Exception {
+ File rootDir = temp.newFolder();
+ // branding file is missing
+ when(server.getRootDir()).thenReturn(rootDir);
+
+ assertThat(underTest.check()).isFalse();
+ }
+}
--- /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.Optional;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+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.health.Health;
+import org.sonar.server.health.TestStandaloneHealthChecker;
+import org.sonar.server.platform.ServerId;
+import org.sonar.server.platform.ServerIdLoader;
+import org.sonar.server.platform.ServerLogging;
+import org.sonar.server.user.SecurityRealmFactory;
+
+import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.process.systeminfo.SystemInfoUtils.attribute;
+import static org.sonar.server.platform.monitoring.SystemInfoTesting.assertThatAttributeIs;
+
+public class StandaloneSystemSectionTest {
+
+ private static final String SERVER_ID_PROPERTY = "Server ID";
+ private static final String SERVER_ID_VALIDATED_PROPERTY = "Server ID validated";
+
+ @Rule
+ public 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 TestStandaloneHealthChecker healthChecker = new TestStandaloneHealthChecker();
+ private OfficialDistribution officialDistribution = mock(OfficialDistribution.class);
+
+ private StandaloneSystemSection underTest = new StandaloneSystemSection(settings.asConfig(), securityRealmFactory, identityProviderRepository, server,
+ serverLogging, serverIdLoader, officialDistribution, healthChecker);
+
+ @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 {
+ when(officialDistribution.check()).thenReturn(true);
+
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThatAttributeIs(protobuf, "Official Distribution", true);
+ }
+
+ @Test
+ public void not_an_official_distribution() throws Exception {
+ when(officialDistribution.check()).thenReturn(false);
+
+ 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");
+ }
+
+ @Test
+ public void return_health() {
+ healthChecker.setHealth(Health.newHealthCheckBuilder()
+ .setStatus(Health.Status.YELLOW)
+ .addCause("foo")
+ .addCause("bar")
+ .build());
+
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThatAttributeIs(protobuf, "Health", "YELLOW");
+ SystemInfoTesting.assertThatAttributeHasOnlyValues(protobuf, "Health Causes", asList("foo", "bar"));
+ }
+
+ @Test
+ public void return_nb_of_processors() {
+ ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
+ assertThat(attribute(protobuf, "Processors").getLongValue()).isGreaterThan(0);
+ }
+}
+++ /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.health.Health;
-import org.sonar.server.health.TestStandaloneHealthChecker;
-import org.sonar.server.platform.ServerId;
-import org.sonar.server.platform.ServerIdLoader;
-import org.sonar.server.platform.ServerLogging;
-import org.sonar.server.user.SecurityRealmFactory;
-
-import static java.util.Arrays.asList;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.sonar.process.systeminfo.SystemInfoUtils.attribute;
-import static org.sonar.server.platform.monitoring.SystemInfoTesting.assertThatAttributeIs;
-
-public class SystemSectionTest {
-
- 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 TestStandaloneHealthChecker healthChecker = new TestStandaloneHealthChecker();
-
- private SystemSection underTest = new SystemSection(settings.asConfig(), securityRealmFactory, identityProviderRepository, server,
- serverLogging, serverIdLoader, healthChecker);
-
- @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, SystemSection.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");
- }
-
- @Test
- public void return_health() {
- healthChecker.setHealth(Health.newHealthCheckBuilder()
- .setStatus(Health.Status.YELLOW)
- .addCause("foo")
- .addCause("bar")
- .build());
-
- ProtobufSystemInfo.Section protobuf = underTest.toProtobuf();
- assertThatAttributeIs(protobuf, "Health", "YELLOW");
- SystemInfoTesting.assertThatAttributeHasOnlyValues(protobuf, "Health Causes", asList("foo", "bar"));
- }
-}
--- /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.cluster;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class NodeInfoTest {
+
+ @Test
+ public void test_equals_and_hashCode() {
+ NodeInfo foo = new NodeInfo("foo");
+ NodeInfo bar = new NodeInfo("bar");
+ NodeInfo bar2 = new NodeInfo("bar");
+
+ assertThat(foo.equals(foo)).isTrue();
+ assertThat(foo.equals(bar)).isFalse();
+ assertThat(bar.equals(bar2)).isTrue();
+
+ assertThat(bar.hashCode()).isEqualTo(bar.hashCode());
+ assertThat(bar.hashCode()).isEqualTo(bar2.hashCode());
+ }
+
+}