aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-process
diff options
context:
space:
mode:
authorJacek <jacek.poreda@sonarsource.com>2021-07-22 13:52:18 +0200
committersonartech <sonartech@sonarsource.com>2021-07-29 20:04:50 +0000
commit78a0a38cd36db3d2c38ffd7ccc494bcd9d366ad9 (patch)
tree9b9c73394cc663c472a0afa1a3b0d9e81d3c6d04 /server/sonar-process
parentc5d6ef5f209111463580bc9bfe7013af30c9ad4b (diff)
downloadsonarqube-78a0a38cd36db3d2c38ffd7ccc494bcd9d366ad9.tar.gz
sonarqube-78a0a38cd36db3d2c38ffd7ccc494bcd9d366ad9.zip
SONAR-15230 Enable DNS lookup in k8s for HZ
Diffstat (limited to 'server/sonar-process')
-rw-r--r--server/sonar-process/build.gradle1
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java1
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMemberBuilder.java78
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/cluster/hz/JoinConfigurationType.java25
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/cluster/hz/MembersResolver.java26
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/cluster/hz/NopMembersResolver.java (renamed from server/sonar-process/src/main/java/org/sonar/process/cluster/hz/InetAdressResolver.java)12
-rw-r--r--server/sonar-process/src/main/java/org/sonar/process/cluster/hz/TcpIpMembersResolver.java74
-rw-r--r--server/sonar-process/src/test/java/org/sonar/process/cluster/hz/HazelcastMemberBuilderTest.java86
-rw-r--r--server/sonar-process/src/test/java/org/sonar/process/cluster/hz/HazelcastMemberImplTest.java2
9 files changed, 200 insertions, 105 deletions
diff --git a/server/sonar-process/build.gradle b/server/sonar-process/build.gradle
index aef277baef4..e075136b8e1 100644
--- a/server/sonar-process/build.gradle
+++ b/server/sonar-process/build.gradle
@@ -16,6 +16,7 @@ dependencies {
compile 'com.google.guava:guava'
compile 'com.google.protobuf:protobuf-java'
compile 'com.hazelcast:hazelcast'
+ compile 'com.hazelcast:hazelcast-kubernetes'
compile 'org.slf4j:jul-to-slf4j'
compile 'org.slf4j:slf4j-api'
compile project(':sonar-core')
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 9217274a281..72c99d1b2d0 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
@@ -114,6 +114,7 @@ public class ProcessProperties {
SOCKS_PROXY_PORT("socksProxyPort"),
CLUSTER_ENABLED("sonar.cluster.enabled", "false"),
+ CLUSTER_KUBERNETES("sonar.cluster.kubernetes", "false"),
CLUSTER_NODE_TYPE("sonar.cluster.node.type"),
CLUSTER_SEARCH_HOSTS("sonar.cluster.search.hosts"),
CLUSTER_HZ_HOSTS("sonar.cluster.hosts"),
diff --git a/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMemberBuilder.java b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMemberBuilder.java
index c2552ef3e20..0e207d7050d 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMemberBuilder.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/HazelcastMemberBuilder.java
@@ -24,36 +24,29 @@ import com.hazelcast.config.JoinConfig;
import com.hazelcast.config.MemberAttributeConfig;
import com.hazelcast.config.NetworkConfig;
import com.hazelcast.core.Hazelcast;
-import com.hazelcast.internal.util.AddressUtil;
-import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Collections;
import java.util.List;
-import java.util.stream.Collectors;
-import javax.annotation.CheckForNull;
-import org.sonar.api.utils.log.Logger;
-import org.sonar.api.utils.log.Loggers;
import org.sonar.process.ProcessId;
import org.sonar.process.cluster.hz.HazelcastMember.Attribute;
-import static java.lang.String.format;
import static java.util.Collections.singletonList;
import static java.util.Objects.requireNonNull;
-import static org.sonar.process.ProcessProperties.Property.CLUSTER_NODE_HZ_PORT;
+import static org.sonar.process.cluster.hz.JoinConfigurationType.KUBERNETES;
+import static org.sonar.process.cluster.hz.JoinConfigurationType.TCP_IP;
public class HazelcastMemberBuilder {
-
- private static final Logger LOG = Loggers.get(HazelcastMemberBuilder.class);
private String nodeName;
private int port;
private ProcessId processId;
private String networkInterface;
- private List<String> members = new ArrayList<>();
- private final InetAdressResolver inetAdressResolver;
+ private final MembersResolver membersResolver;
+ private final List<String> members = new ArrayList<>();
+ private final JoinConfigurationType type;
- public HazelcastMemberBuilder(InetAdressResolver inetAdressResolver) {
- this.inetAdressResolver = inetAdressResolver;
+ public HazelcastMemberBuilder(JoinConfigurationType type) {
+ this.type = type;
+ this.membersResolver = TCP_IP.equals(type) ? new TcpIpMembersResolver() : new NopMembersResolver();
}
public HazelcastMemberBuilder setNodeName(String s) {
@@ -79,49 +72,14 @@ public class HazelcastMemberBuilder {
return this;
}
- @CheckForNull
- List<String> getMembers() {
- return members;
- }
-
/**
- * Adds references to cluster members. If port is missing, then default
- * port is automatically added.
+ * Adds references to cluster members
*/
- public HazelcastMemberBuilder setMembers(Collection<String> c) {
- this.members.addAll(c.stream().map(this::extractMembers).flatMap(Collection::stream).collect(Collectors.toList()));
+ public HazelcastMemberBuilder setMembers(Collection<String> members) {
+ this.members.addAll(members);
return this;
}
- private List<String> extractMembers(String host) {
- LOG.debug("Trying to add host: " + host);
- String hostStripped = host.split(":")[0];
- if (AddressUtil.isIpAddress(hostStripped)) {
- LOG.debug("Found ip based host config for host: " + host);
- return Collections.singletonList(host.contains(":") ? host : format("%s:%s", host, CLUSTER_NODE_HZ_PORT.getDefaultValue()));
- } else {
- List<String> membersToAdd = new ArrayList<>();
- for (String memberIp : getAllByName(hostStripped)) {
- String prefix = memberIp.split("/")[1];
- LOG.debug("Found IP for: " + hostStripped + " : " + prefix);
- String memberPort = host.contains(":") ? host.split(":")[1] : CLUSTER_NODE_HZ_PORT.getDefaultValue();
- String member = prefix + ":" + memberPort;
- membersToAdd.add(member);
- }
- return membersToAdd;
- }
- }
-
- List<String> getAllByName(String hostname) {
- LOG.debug("Trying to resolve Hostname: " + hostname);
- try {
- return inetAdressResolver.getAllByName(hostname);
- } catch (UnknownHostException e) {
- LOG.error("Host could not be found\n" + e.getMessage());
- }
- return new ArrayList<>();
- }
-
public HazelcastMember build() {
Config config = new Config();
// do not use the value defined by property sonar.cluster.name.
@@ -140,12 +98,20 @@ public class HazelcastMemberBuilder {
.setEnabled(true)
.setInterfaces(singletonList(requireNonNull(networkInterface, "Network interface is missing")));
- // Only allowing TCP/IP configuration
JoinConfig joinConfig = netConfig.getJoin();
joinConfig.getAwsConfig().setEnabled(false);
joinConfig.getMulticastConfig().setEnabled(false);
- joinConfig.getTcpIpConfig().setEnabled(true);
- joinConfig.getTcpIpConfig().setMembers(requireNonNull(members, "Members are missing"));
+
+ List<String> resolvedNodes = membersResolver.resolveMembers(this.members);
+ if (KUBERNETES.equals(type)) {
+ joinConfig.getKubernetesConfig().setEnabled(true)
+ .setProperty("service-dns", requireNonNull(resolvedNodes.get(0), "Service DNS is missing"))
+ .setProperty("service-port", "9003");
+ } else {
+ joinConfig.getTcpIpConfig().setEnabled(true);
+ joinConfig.getTcpIpConfig().setMembers(requireNonNull(resolvedNodes, "Members are missing"));
+ }
+
// We are not using the partition group of Hazelcast, so disabling it
config.getPartitionGroupConfig().setEnabled(false);
diff --git a/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/JoinConfigurationType.java b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/JoinConfigurationType.java
new file mode 100644
index 00000000000..cb7765c62fb
--- /dev/null
+++ b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/JoinConfigurationType.java
@@ -0,0 +1,25 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.hz;
+
+public enum JoinConfigurationType {
+ TCP_IP,
+ KUBERNETES
+}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/MembersResolver.java b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/MembersResolver.java
new file mode 100644
index 00000000000..3419c8b0bc2
--- /dev/null
+++ b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/MembersResolver.java
@@ -0,0 +1,26 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.hz;
+
+import java.util.List;
+
+interface MembersResolver {
+ List<String> resolveMembers(List<String> membersToResolve);
+}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/InetAdressResolver.java b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/NopMembersResolver.java
index 3211a94ca9f..fbafb4f90f7 100644
--- a/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/InetAdressResolver.java
+++ b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/NopMembersResolver.java
@@ -19,16 +19,12 @@
*/
package org.sonar.process.cluster.hz;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
import java.util.List;
-import java.util.stream.Collectors;
-public class InetAdressResolver {
-
- public List<String> getAllByName(String hostname) throws UnknownHostException {
- return Arrays.stream(InetAddress.getAllByName(hostname)).map(InetAddress::toString).collect(Collectors.toList());
+class NopMembersResolver implements MembersResolver {
+ @Override
+ public List<String> resolveMembers(List<String> membersToResolve) {
+ return membersToResolve;
}
}
diff --git a/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/TcpIpMembersResolver.java b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/TcpIpMembersResolver.java
new file mode 100644
index 00000000000..89e7ef68fc0
--- /dev/null
+++ b/server/sonar-process/src/main/java/org/sonar/process/cluster/hz/TcpIpMembersResolver.java
@@ -0,0 +1,74 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.hz;
+
+import com.hazelcast.internal.util.AddressUtil;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
+
+import static java.lang.String.format;
+import static org.sonar.process.ProcessProperties.Property.CLUSTER_NODE_HZ_PORT;
+
+class TcpIpMembersResolver implements MembersResolver {
+ private static final Logger LOG = Loggers.get(TcpIpMembersResolver.class);
+
+ @Override
+ public List<String> resolveMembers(List<String> membersToResolve) {
+ return membersToResolve.stream().map(this::extractMembers).flatMap(Collection::stream).collect(Collectors.toList());
+ }
+
+ private List<String> extractMembers(String host) {
+ LOG.debug("Trying to add host: " + host);
+ String hostStripped = host.split(":")[0];
+ if (AddressUtil.isIpAddress(hostStripped)) {
+ LOG.debug("Found ip based host config for host: " + host);
+ return Collections.singletonList(host.contains(":") ? host : format("%s:%s", host, CLUSTER_NODE_HZ_PORT.getDefaultValue()));
+ } else {
+ List<String> membersToAdd = new ArrayList<>();
+ for (String memberIp : getAllByName(hostStripped)) {
+ String prefix = memberIp.split("/")[1];
+ LOG.debug("Found IP for: " + hostStripped + " : " + prefix);
+ String memberPort = host.contains(":") ? host.split(":")[1] : CLUSTER_NODE_HZ_PORT.getDefaultValue();
+ String member = prefix + ":" + memberPort;
+ membersToAdd.add(member);
+ }
+ return membersToAdd;
+ }
+ }
+
+ private List<String> getAllByName(String hostname) {
+ LOG.debug("Trying to resolve Hostname: " + hostname);
+ try {
+ return Arrays.stream(InetAddress.getAllByName(hostname)).map(InetAddress::toString).collect(Collectors.toList());
+ } catch (UnknownHostException e) {
+ LOG.error("Host could not be found: " + e.getMessage());
+ }
+ return new ArrayList<>();
+ }
+
+}
diff --git a/server/sonar-process/src/test/java/org/sonar/process/cluster/hz/HazelcastMemberBuilderTest.java b/server/sonar-process/src/test/java/org/sonar/process/cluster/hz/HazelcastMemberBuilderTest.java
index ff730e80f51..054c05cda77 100644
--- a/server/sonar-process/src/test/java/org/sonar/process/cluster/hz/HazelcastMemberBuilderTest.java
+++ b/server/sonar-process/src/test/java/org/sonar/process/cluster/hz/HazelcastMemberBuilderTest.java
@@ -20,58 +20,74 @@
package org.sonar.process.cluster.hz;
import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.List;
-import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.DisableOnDebug;
-import org.junit.rules.ExpectedException;
import org.junit.rules.TestRule;
import org.junit.rules.Timeout;
import org.sonar.process.NetworkUtilsImpl;
import org.sonar.process.ProcessId;
-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.ProcessProperties.Property.CLUSTER_NODE_HZ_PORT;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
public class HazelcastMemberBuilderTest {
@Rule
- public ExpectedException expectedException = ExpectedException.none();
- @Rule
public TestRule safeguardTimeout = new DisableOnDebug(Timeout.seconds(60));
// use loopback for support of offline builds
private final InetAddress loopback = InetAddress.getLoopbackAddress();
- private final InetAdressResolver inetAdressResolver = mock(InetAdressResolver.class);
- private final HazelcastMemberBuilder underTest = new HazelcastMemberBuilder(inetAdressResolver);
-
- @Before
- public void before() throws UnknownHostException {
- when(inetAdressResolver.getAllByName("foo")).thenReturn(Collections.singletonList("foo/5.6.7.8"));
- when(inetAdressResolver.getAllByName("bar")).thenReturn(Collections.singletonList("bar/8.7.6.5"));
- when(inetAdressResolver.getAllByName("wizz")).thenReturn(Arrays.asList("wizz/1.2.3.4", "wizz/2.3.4.5", "wizz/3.4.5.6"));
- when(inetAdressResolver.getAllByName("ninja")).thenReturn(Arrays.asList("ninja/4.5.6.7", "ninja/5.6.7.8"));
+
+ @Test
+ public void build_tcp_ip_member_hostaddress() {
+ HazelcastMember member = new HazelcastMemberBuilder(JoinConfigurationType.TCP_IP)
+ .setMembers(Collections.singletonList(loopback.getHostAddress()))
+ .setProcessId(ProcessId.COMPUTE_ENGINE)
+ .setNodeName("bar")
+ .setPort(NetworkUtilsImpl.INSTANCE.getNextLoopbackAvailablePort())
+ .setNetworkInterface(loopback.getHostAddress())
+ .build();
+
+ assertThat(member.getUuid()).isNotNull();
+ assertThat(member.getClusterTime()).isPositive();
+ assertThat(member.getCluster().getMembers()).hasSize(1);
+ assertThat(member.getMemberUuids()).containsOnlyOnce(member.getUuid());
+
+ assertThat(member.getAtomicReference("baz")).isNotNull();
+ assertThat(member.getLock("baz")).isNotNull();
+ assertThat(member.getReplicatedMap("baz")).isNotNull();
+
+ member.close();
}
@Test
- public void testMultipleIPsByHostname() {
- underTest.setMembers(asList("wizz:9001", "ninja"));
+ public void build_tcp_ip_member_hostname() {
+ HazelcastMember member = new HazelcastMemberBuilder(JoinConfigurationType.TCP_IP)
+ .setMembers(Collections.singletonList(loopback.getHostName()))
+ .setProcessId(ProcessId.COMPUTE_ENGINE)
+ .setNodeName("bar")
+ .setPort(NetworkUtilsImpl.INSTANCE.getNextLoopbackAvailablePort())
+ .setNetworkInterface(loopback.getHostAddress())
+ .build();
+
+ assertThat(member.getUuid()).isNotNull();
+ assertThat(member.getClusterTime()).isPositive();
+ assertThat(member.getCluster().getMembers()).hasSize(1);
+ assertThat(member.getMemberUuids()).containsOnlyOnce(member.getUuid());
- List<String> members = underTest.getMembers();
- assertThat(members).containsExactlyInAnyOrder("1.2.3.4:9001", "2.3.4.5:9001", "3.4.5.6:9001", "4.5.6.7:9003", "5.6.7.8:9003");
+ assertThat(member.getAtomicReference("baz")).isNotNull();
+ assertThat(member.getLock("baz")).isNotNull();
+ assertThat(member.getReplicatedMap("baz")).isNotNull();
+ member.close();
}
@Test
- public void build_member() {
- HazelcastMember member = underTest
+ public void build_kubernetes_member() {
+ HazelcastMember member = new HazelcastMemberBuilder(JoinConfigurationType.KUBERNETES)
+ .setMembers(Collections.singletonList(loopback.getHostAddress()))
.setProcessId(ProcessId.COMPUTE_ENGINE)
.setNodeName("bar")
.setPort(NetworkUtilsImpl.INSTANCE.getNextLoopbackAvailablePort())
@@ -91,20 +107,10 @@ public class HazelcastMemberBuilderTest {
}
@Test
- public void default_port_is_added_when_missing() {
- underTest.setMembers(asList("foo", "bar:9100", "1.2.3.4"));
-
- assertThat(underTest.getMembers()).containsExactly(
- "5.6.7.8:" + CLUSTER_NODE_HZ_PORT.getDefaultValue(),
- "8.7.6.5:9100",
- "1.2.3.4:" + CLUSTER_NODE_HZ_PORT.getDefaultValue());
- }
-
- @Test
public void fail_if_elasticsearch_process() {
- expectedException.expect(IllegalArgumentException.class);
- expectedException.expectMessage("Hazelcast must not be enabled on Elasticsearch node");
-
- underTest.setProcessId(ProcessId.ELASTICSEARCH);
+ var builder = new HazelcastMemberBuilder(JoinConfigurationType.TCP_IP);
+ assertThatThrownBy(() -> builder.setProcessId(ProcessId.ELASTICSEARCH))
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Hazelcast must not be enabled on Elasticsearch node");
}
}
diff --git a/server/sonar-process/src/test/java/org/sonar/process/cluster/hz/HazelcastMemberImplTest.java b/server/sonar-process/src/test/java/org/sonar/process/cluster/hz/HazelcastMemberImplTest.java
index 039ccb3b440..62202667554 100644
--- a/server/sonar-process/src/test/java/org/sonar/process/cluster/hz/HazelcastMemberImplTest.java
+++ b/server/sonar-process/src/test/java/org/sonar/process/cluster/hz/HazelcastMemberImplTest.java
@@ -110,7 +110,7 @@ public class HazelcastMemberImplTest {
}
private static HazelcastMember newHzMember(int port, int... otherPorts) {
- return new HazelcastMemberBuilder(new InetAdressResolver())
+ return new HazelcastMemberBuilder(JoinConfigurationType.TCP_IP)
.setProcessId(ProcessId.COMPUTE_ENGINE)
.setNodeName("name" + port)
.setPort(port)