diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2017-08-25 11:54:26 +0200 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2017-09-13 15:50:49 +0200 |
commit | 80269a5d22553335f22f3e8a8a5840724fb154f9 (patch) | |
tree | df2a88bb4ae61251040499ec77f2d217246512a1 /server/sonar-process/src | |
parent | 904cd8b327790c31d1abe0bceb0007015e74dfdf (diff) | |
download | sonarqube-80269a5d22553335f22f3e8a8a5840724fb154f9.tar.gz sonarqube-80269a5d22553335f22f3e8a8a5840724fb154f9.zip |
SONAR-9741 move shared cluster related classes to sonar-cluster
Diffstat (limited to 'server/sonar-process/src')
8 files changed, 26 insertions, 353 deletions
diff --git a/server/sonar-process/src/main/java/org/sonar/process/NetworkUtils.java b/server/sonar-process/src/main/java/org/sonar/process/NetworkUtils.java deleted file mode 100644 index d643cf9ca75..00000000000 --- a/server/sonar-process/src/main/java/org/sonar/process/NetworkUtils.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.process; - -import java.io.IOException; -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.ServerSocket; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; - -import static java.util.Collections.list; -import static org.apache.commons.lang.StringUtils.isBlank; - -public final class NetworkUtils { - - private static final Set<Integer> ALREADY_ALLOCATED = new HashSet<>(); - private static final int MAX_TRIES = 50; - - private NetworkUtils() { - // prevent instantiation - } - - public static int getNextAvailablePort(InetAddress address) { - return getNextAvailablePort(address, PortAllocator.INSTANCE); - } - - /** - * Identifying the localhost machine - * It will try to retrieve the hostname - * - * @return "hostname" - */ - public static String getHostname() { - String hostname; - try { - hostname = InetAddress.getLocalHost().getHostName(); - } catch (UnknownHostException e) { - hostname = "unresolved hostname"; - } - - return hostname; - } - - /** - * Identifying the IPs addresses - * - * @return "ipv4_1, ipv4_2" - */ - public static String getIPAddresses() { - String ips; - - try { - ips = list(NetworkInterface.getNetworkInterfaces()).stream() - .flatMap(netif -> list(netif.getInetAddresses()).stream() - .filter(inetAddress -> - // Removing IPv6 for the time being - inetAddress instanceof Inet4Address && - // Removing loopback addresses, useless for identifying a server - !inetAddress.isLoopbackAddress() && - // Removing interfaces without IPs - !isBlank(inetAddress.getHostAddress())) - .map(InetAddress::getHostAddress)) - .filter(p -> !isBlank(p)) - .collect(Collectors.joining(",")); - } catch (SocketException e) { - ips = "unresolved IPs"; - } - - return ips; - } - - /** - * Warning - the allocated ports are kept in memory and are never clean-up. Besides the memory consumption, - * that means that ports already allocated are never freed. As a consequence - * no more than ~64512 calls to this method are allowed. - */ - static int getNextAvailablePort(InetAddress address, PortAllocator portAllocator) { - for (int i = 0; i < MAX_TRIES; i++) { - int port = portAllocator.getAvailable(address); - if (isValidPort(port)) { - ALREADY_ALLOCATED.add(port); - return port; - } - } - throw new IllegalStateException("Fail to find an available port on " + address); - } - - private static boolean isValidPort(int port) { - return port > 1023 && !ALREADY_ALLOCATED.contains(port); - } - - static class PortAllocator { - private static final PortAllocator INSTANCE = new PortAllocator(); - - int getAvailable(InetAddress address) { - try (ServerSocket socket = new ServerSocket(0, 50, address)) { - return socket.getLocalPort(); - } catch (IOException e) { - throw new IllegalStateException("Fail to find an available port on " + address, e); - } - } - } -} diff --git a/server/sonar-process/src/main/java/org/sonar/process/NodeType.java b/server/sonar-process/src/main/java/org/sonar/process/NodeType.java index 63c532b687d..ecd8e44bc95 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/NodeType.java +++ b/server/sonar-process/src/main/java/org/sonar/process/NodeType.java @@ -20,6 +20,7 @@ package org.sonar.process; import static java.util.Arrays.stream; +import static org.sonar.cluster.ClusterProperties.CLUSTER_NODE_TYPE; public enum NodeType { APPLICATION("application"), SEARCH("search"); @@ -38,7 +39,7 @@ public enum NodeType { return stream(values()) .filter(t -> nodeType.equals(t.value)) .findFirst() - .orElseThrow(() -> new IllegalArgumentException("Invalid value for [" + ProcessProperties.CLUSTER_NODE_TYPE + "]: [" + nodeType + "]")); + .orElseThrow(() -> new IllegalArgumentException("Invalid value for [" + CLUSTER_NODE_TYPE + "]: [" + nodeType + "]")); } public static boolean isValid(String nodeType) { diff --git a/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java b/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java index fa35616bc06..24b9be0885f 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java +++ b/server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java @@ -23,26 +23,15 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Map; import java.util.Properties; +import org.sonar.NetworkUtils; + +import static org.sonar.cluster.ClusterProperties.putClusterDefaults; /** * Constants shared by search, web server and app processes. * They are almost all the properties defined in conf/sonar.properties. */ public class ProcessProperties { - public static final String CLUSTER_ENABLED = "sonar.cluster.enabled"; - public static final String CLUSTER_NODE_TYPE = "sonar.cluster.node.type"; - public static final String CLUSTER_SEARCH_HOSTS = "sonar.cluster.search.hosts"; - public static final String CLUSTER_HOSTS = "sonar.cluster.hosts"; - public static final String CLUSTER_NODE_PORT = "sonar.cluster.node.port"; - public static final String CLUSTER_NODE_HOST = "sonar.cluster.node.host"; - public static final String CLUSTER_NODE_NAME = "sonar.cluster.node.name"; - public static final String CLUSTER_NAME = "sonar.cluster.name"; - public static final String HAZELCAST_LOG_LEVEL = "sonar.log.level.app.hazelcast"; - public static final String CLUSTER_WEB_LEADER = "sonar.cluster.web.startupLeader"; - // Internal property used by sonar-application to share the local endpoint of Hazelcast - public static final String CLUSTER_LOCALENDPOINT = "sonar.cluster.hazelcast.localEndPoint"; - // Internal property used by sonar-application to share the local UUID of the Hazelcast member - public static final String CLUSTER_MEMBERUUID = "sonar.cluster.hazelcast.memberUUID"; public static final String JDBC_URL = "sonar.jdbc.url"; public static final String JDBC_DRIVER_PATH = "sonar.jdbc.driverPath"; @@ -137,12 +126,7 @@ public class ProcessProperties { defaults.put(JDBC_MIN_EVICTABLE_IDLE_TIME_MILLIS, "600000"); defaults.put(JDBC_TIME_BETWEEN_EVICTION_RUNS_MILLIS, "30000"); - defaults.put(CLUSTER_ENABLED, "false"); - defaults.put(CLUSTER_NAME, "sonarqube"); - defaults.put(CLUSTER_NODE_HOST, ""); - defaults.put(CLUSTER_HOSTS, ""); - defaults.put(CLUSTER_NODE_PORT, "9003"); - defaults.put(HAZELCAST_LOG_LEVEL, "WARN"); + putClusterDefaults(defaults); return defaults; } diff --git a/server/sonar-process/src/main/java/org/sonar/process/cluster/ClusterObjectKeys.java b/server/sonar-process/src/main/java/org/sonar/process/cluster/ClusterObjectKeys.java deleted file mode 100644 index 4fd578d0429..00000000000 --- a/server/sonar-process/src/main/java/org/sonar/process/cluster/ClusterObjectKeys.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -package org.sonar.process.cluster; - -/** - * This class holds all object keys accessible via Hazelcast - */ -public final class ClusterObjectKeys { - - private ClusterObjectKeys() { - // Holder for clustered objects - } - - /** - * The key of replicated map that hold all operational processes - */ - public static final String OPERATIONAL_PROCESSES = "OPERATIONAL_PROCESSES"; - /** - * The key of atomic reference holding the leader UUID - */ - public static final String LEADER = "LEADER"; - /** - * The key of the hostname attribute of a member - */ - public static final String HOSTNAME = "HOSTNAME"; - /** - * The key of the ips list attribute of a member - */ - public static final String IP_ADDRESSES = "IP_ADDRESSES"; - /** - * The key of the node name attribute of a member - */ - public static final String NODE_NAME = "NODE_NAME"; - /** - * The role of the sonar-application inside the SonarQube cluster - * {@link org.sonar.process.NodeType} - */ - public static final String NODE_TYPE = "NODE_TYPE"; - /** - * The key of atomic reference holding the SonarQube version of the cluster - */ - public static final String SONARQUBE_VERSION = "SONARQUBE_VERSION"; - /** - * The key of atomic reference holding the name of the cluster (used for precondition checks) - */ - public static final String CLUSTER_NAME = "CLUSTER_NAME"; - /** - * The key of the Set holding the UUIDs of clients - */ - public static final String CLIENT_UUIDS = "CLIENT_UUIDS"; - /** - * The key of replicated map holding the CeWorker UUIDs - */ - public static final String WORKER_UUIDS = "WORKER_UUIDS"; - - /** - * The key of the lock for executing CE_CLEANING_JOB - * {@link CeCleaningSchedulerImpl} - */ - public static final String CE_CLEANING_JOB_LOCK = "CE_CLEANING_JOB_LOCK"; -} diff --git a/server/sonar-process/src/main/java/org/sonar/process/cluster/package-info.java b/server/sonar-process/src/main/java/org/sonar/process/cluster/package-info.java deleted file mode 100644 index 65df8dff487..00000000000 --- a/server/sonar-process/src/main/java/org/sonar/process/cluster/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -@ParametersAreNonnullByDefault -package org.sonar.process.cluster; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/server/sonar-process/src/main/java/org/sonar/process/es/EsSettings.java b/server/sonar-process/src/main/java/org/sonar/process/es/EsSettings.java index d690821d8f9..f06380774ee 100644 --- a/server/sonar-process/src/main/java/org/sonar/process/es/EsSettings.java +++ b/server/sonar-process/src/main/java/org/sonar/process/es/EsSettings.java @@ -34,7 +34,10 @@ import org.sonar.process.ProcessProperties; import org.sonar.process.Props; import static java.lang.String.valueOf; -import static org.sonar.process.ProcessProperties.CLUSTER_NODE_NAME; +import static org.sonar.cluster.ClusterProperties.CLUSTER_ENABLED; +import static org.sonar.cluster.ClusterProperties.CLUSTER_NAME; +import static org.sonar.cluster.ClusterProperties.CLUSTER_NODE_NAME; +import static org.sonar.cluster.ClusterProperties.CLUSTER_SEARCH_HOSTS; import static org.sonar.process.ProcessProperties.SEARCH_MARVEL_HOSTS; public class EsSettings { @@ -53,8 +56,8 @@ public class EsSettings { this.props = props; this.fileSystem = fileSystem; - this.clusterName = props.nonNullValue(ProcessProperties.CLUSTER_NAME); - this.clusterEnabled = props.valueAsBoolean(ProcessProperties.CLUSTER_ENABLED); + this.clusterName = props.nonNullValue(CLUSTER_NAME); + this.clusterEnabled = props.valueAsBoolean(CLUSTER_ENABLED); if (this.clusterEnabled) { this.nodeName = props.value(CLUSTER_NODE_NAME, "sonarqube-" + UUID.randomUUID().toString()); } else { @@ -124,7 +127,7 @@ public class EsSettings { minimumMasterNodes = props.valueAsInt(ProcessProperties.SEARCH_MINIMUM_MASTER_NODES, 2); initialStateTimeOut = props.value(ProcessProperties.SEARCH_INITIAL_STATE_TIMEOUT, "120s"); - String hosts = props.value(ProcessProperties.CLUSTER_SEARCH_HOSTS, ""); + String hosts = props.value(CLUSTER_SEARCH_HOSTS, ""); LOGGER.info("Elasticsearch cluster enabled. Connect to hosts [{}]", hosts); builder.put("discovery.zen.ping.unicast.hosts", hosts); } diff --git a/server/sonar-process/src/test/java/org/sonar/process/NetworkUtilsTest.java b/server/sonar-process/src/test/java/org/sonar/process/NetworkUtilsTest.java deleted file mode 100644 index 6450790490d..00000000000 --- a/server/sonar-process/src/test/java/org/sonar/process/NetworkUtilsTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2017 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.process; - -import java.net.InetAddress; -import java.util.HashSet; -import java.util.Set; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static java.net.InetAddress.getLoopbackAddress; -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.sonar.process.NetworkUtils.getNextAvailablePort; - -public class NetworkUtilsTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Test - public void getNextAvailablePort_never_returns_the_same_port_in_current_jvm() { - Set<Integer> ports = new HashSet<>(); - for (int i = 0; i < 100; i++) { - int port = getNextAvailablePort(getLoopbackAddress()); - assertThat(port).isGreaterThan(1_023); - ports.add(port); - } - assertThat(ports).hasSize(100); - } - - @Test - public void getNextAvailablePort_retries_to_get_available_port_when_port_has_already_been_allocated() { - NetworkUtils.PortAllocator portAllocator = mock(NetworkUtils.PortAllocator.class); - when(portAllocator.getAvailable(any(InetAddress.class))).thenReturn(9_000, 9_000, 9_000, 9_100); - - InetAddress address = getLoopbackAddress(); - assertThat(getNextAvailablePort(address, portAllocator)).isEqualTo(9_000); - assertThat(getNextAvailablePort(address, portAllocator)).isEqualTo(9_100); - } - - @Test - public void getNextAvailablePort_does_not_return_special_ports() { - NetworkUtils.PortAllocator portAllocator = mock(NetworkUtils.PortAllocator.class); - when(portAllocator.getAvailable(any(InetAddress.class))).thenReturn(900, 903, 1_059); - - // the two first ports are banned because < 1023, so 1_059 is returned - assertThat(getNextAvailablePort(getLoopbackAddress(), portAllocator)).isEqualTo(1_059); - } - - @Test - public void getNextAvailablePort_throws_ISE_if_too_many_attempts() { - NetworkUtils.PortAllocator portAllocator = mock(NetworkUtils.PortAllocator.class); - when(portAllocator.getAvailable(any(InetAddress.class))).thenReturn(900); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("Fail to find an available port on "); - - getNextAvailablePort(getLoopbackAddress(), portAllocator); - } - - @Test - public void getHostname_must_return_a_value() { - assertThat(NetworkUtils.getHostname()).containsPattern(".+"); - } - - @Test - public void getIPAddresses_must_return_a_value() { - assertThat(NetworkUtils.getIPAddresses()).matches("(\\d+\\.\\d+\\.\\d+\\.\\d+,?)+"); - } -} diff --git a/server/sonar-process/src/test/java/org/sonar/process/es/EsSettingsTest.java b/server/sonar-process/src/test/java/org/sonar/process/es/EsSettingsTest.java index 643e80c859f..c11fc2589a0 100644 --- a/server/sonar-process/src/test/java/org/sonar/process/es/EsSettingsTest.java +++ b/server/sonar-process/src/test/java/org/sonar/process/es/EsSettingsTest.java @@ -28,12 +28,15 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; +import org.sonar.cluster.ClusterProperties; import org.sonar.process.ProcessProperties; import org.sonar.process.Props; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.sonar.cluster.ClusterProperties.CLUSTER_NAME; +import static org.sonar.cluster.ClusterProperties.CLUSTER_SEARCH_HOSTS; public class EsSettingsTest { @@ -55,7 +58,7 @@ public class EsSettingsTest { props.set(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath()); props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath()); props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath()); - props.set(ProcessProperties.CLUSTER_NAME, "sonarqube"); + props.set(CLUSTER_NAME, "sonarqube"); EsSettings esSettings = new EsSettings(props, new EsFileSystem(props)); @@ -91,9 +94,9 @@ public class EsSettingsTest { props.set(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath()); props.set(ProcessProperties.PATH_TEMP, temp.newFolder().getAbsolutePath()); props.set(ProcessProperties.PATH_LOGS, temp.newFolder().getAbsolutePath()); - props.set(ProcessProperties.CLUSTER_NAME, "sonarqube-1"); - props.set(ProcessProperties.CLUSTER_ENABLED, "true"); - props.set(ProcessProperties.CLUSTER_NODE_NAME, "node-1"); + props.set(ClusterProperties.CLUSTER_NAME, "sonarqube-1"); + props.set(ClusterProperties.CLUSTER_ENABLED, "true"); + props.set(ClusterProperties.CLUSTER_NODE_NAME, "node-1"); EsSettings esSettings = new EsSettings(props, new EsFileSystem(props)); @@ -106,8 +109,8 @@ public class EsSettingsTest { public void test_node_name_default_for_cluster_mode() throws Exception { File homeDir = temp.newFolder(); Props props = new Props(new Properties()); - props.set(ProcessProperties.CLUSTER_NAME, "sonarqube"); - props.set(ProcessProperties.CLUSTER_ENABLED, "true"); + props.set(ClusterProperties.CLUSTER_NAME, "sonarqube"); + props.set(ClusterProperties.CLUSTER_ENABLED, "true"); props.set(ProcessProperties.SEARCH_PORT, "1234"); props.set(ProcessProperties.SEARCH_HOST, "127.0.0.1"); props.set(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath()); @@ -122,8 +125,8 @@ public class EsSettingsTest { public void test_node_name_default_for_standalone_mode() throws Exception { File homeDir = temp.newFolder(); Props props = new Props(new Properties()); - props.set(ProcessProperties.CLUSTER_NAME, "sonarqube"); - props.set(ProcessProperties.CLUSTER_ENABLED, "false"); + props.set(ClusterProperties.CLUSTER_NAME, "sonarqube"); + props.set(ClusterProperties.CLUSTER_ENABLED, "false"); props.set(ProcessProperties.SEARCH_PORT, "1234"); props.set(ProcessProperties.SEARCH_HOST, "127.0.0.1"); props.set(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath()); @@ -153,7 +156,7 @@ public class EsSettingsTest { @Test public void set_discovery_settings_if_cluster_is_enabled() throws Exception { Props props = minProps(CLUSTER_ENABLED); - props.set(ProcessProperties.CLUSTER_SEARCH_HOSTS, "1.2.3.4:9000,1.2.3.5:8080"); + props.set(CLUSTER_SEARCH_HOSTS, "1.2.3.4:9000,1.2.3.5:8080"); Map<String, String> settings = new EsSettings(props, new EsFileSystem(props)).build(); assertThat(settings.get("discovery.zen.ping.unicast.hosts")).isEqualTo("1.2.3.4:9000,1.2.3.5:8080"); @@ -246,7 +249,7 @@ public class EsSettingsTest { Props props = new Props(new Properties()); ProcessProperties.completeDefaults(props); props.set(ProcessProperties.PATH_HOME, homeDir.getAbsolutePath()); - props.set(ProcessProperties.CLUSTER_ENABLED, Boolean.toString(cluster)); + props.set(ClusterProperties.CLUSTER_ENABLED, Boolean.toString(cluster)); return props; } } |