Kaynağa Gözat

SONAR-12955 support IPv6 in cluster properties

and consistently valid adresses
tags/8.2.0.32929
Sébastien Lesaint 4 yıl önce
ebeveyn
işleme
accb6a680a

+ 105
- 42
server/sonar-main/src/main/java/org/sonar/application/config/ClusterSettings.java Dosyayı Görüntüle

@@ -19,26 +19,31 @@
*/
package org.sonar.application.config;

import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import com.google.common.net.HostAndPort;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import org.apache.commons.lang.StringUtils;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import org.slf4j.LoggerFactory;
import org.sonar.core.util.stream.MoreCollectors;
import org.sonar.process.MessageException;
import org.sonar.process.NetworkUtils;
import org.sonar.process.ProcessId;
import org.sonar.process.ProcessProperties.Property;
import org.sonar.process.Props;
import org.sonar.process.cluster.NodeType;

import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.Arrays.stream;
import static java.util.Collections.singleton;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.joining;
import static org.apache.commons.lang.StringUtils.isBlank;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static org.sonar.process.ProcessProperties.Property.AUTH_JWT_SECRET;
import static org.sonar.process.ProcessProperties.Property.CLUSTER_ENABLED;
import static org.sonar.process.ProcessProperties.Property.CLUSTER_HZ_HOSTS;
@@ -49,6 +54,7 @@ import static org.sonar.process.ProcessProperties.Property.CLUSTER_SEARCH_HOSTS;
import static org.sonar.process.ProcessProperties.Property.CLUSTER_WEB_STARTUP_LEADER;
import static org.sonar.process.ProcessProperties.Property.JDBC_URL;
import static org.sonar.process.ProcessProperties.Property.SEARCH_HOST;
import static org.sonar.process.ProcessProperties.Property.SEARCH_PORT;

public class ClusterSettings implements Consumer<Props> {

@@ -71,16 +77,23 @@ public class ClusterSettings implements Consumer<Props> {
throw new MessageException(format("Property [%s] is forbidden", CLUSTER_WEB_STARTUP_LEADER.getKey()));
}

checkNodeSpecificProperties(props);
checkCommonProperties(props);
}

private void checkNodeSpecificProperties(Props props) {
NodeType nodeType = toNodeType(props);
switch (nodeType) {
case APPLICATION:
ensureNotH2(props);
requireValue(props, AUTH_JWT_SECRET.getKey());
ensureNotLoopbackAddresses(props, CLUSTER_HZ_HOSTS.getKey());
requireValue(props, AUTH_JWT_SECRET);
Set<AddressAndPort> hzNodes = parseHosts(CLUSTER_HZ_HOSTS, requireValue(props, CLUSTER_HZ_HOSTS));
ensureNotLoopbackAddresses(CLUSTER_HZ_HOSTS, hzNodes);
break;
case SEARCH:
requireValue(props, SEARCH_HOST.getKey());
ensureLocalButNotLoopbackAddress(props, SEARCH_HOST.getKey());
AddressAndPort searchHost = parseAndCheckHost(SEARCH_HOST, requireValue(props, SEARCH_HOST));
ensureLocalButNotLoopbackAddress(SEARCH_HOST, searchHost);
requireValue(props, SEARCH_PORT);
if (props.contains(CLUSTER_NODE_HZ_PORT.getKey())) {
LoggerFactory.getLogger(getClass()).warn("Property {} is ignored on search nodes since 7.2", CLUSTER_NODE_HZ_PORT.getKey());
}
@@ -88,13 +101,50 @@ public class ClusterSettings implements Consumer<Props> {
default:
throw new UnsupportedOperationException("Unknown value: " + nodeType);
}
requireValue(props, CLUSTER_NODE_HOST.getKey());
ensureLocalButNotLoopbackAddress(props, CLUSTER_NODE_HOST.getKey());
ensureNotLoopbackAddresses(props, CLUSTER_SEARCH_HOSTS.getKey());
}

private void checkCommonProperties(Props props) {
AddressAndPort clusterNodeHost = parseAndCheckHost(CLUSTER_NODE_HOST, requireValue(props, CLUSTER_NODE_HOST));
ensureLocalButNotLoopbackAddress(CLUSTER_NODE_HOST, clusterNodeHost);
Set<AddressAndPort> searchHosts = parseHosts(CLUSTER_SEARCH_HOSTS, requireValue(props, CLUSTER_SEARCH_HOSTS));
ensureNotLoopbackAddresses(CLUSTER_SEARCH_HOSTS, searchHosts);
}

private Set<AddressAndPort> parseHosts(Property property, String value) {
Set<AddressAndPort> res = stream(value.split(","))
.filter(Objects::nonNull)
.map(String::trim)
.map(ClusterSettings::parseHost)
.collect(toSet());
checkValidHosts(property, res);
return res;
}

private void checkValidHosts(Property property, Set<AddressAndPort> addressAndPorts) {
List<String> invalidHosts = addressAndPorts.stream()
.map(AddressAndPort::getHost)
.filter(t -> !network.toInetAddress(t).isPresent())
.sorted()
.collect(toList());
if (!invalidHosts.isEmpty()) {
throw new MessageException(format("Address in property %s is not a valid address: %s",
property.getKey(), String.join(", ", invalidHosts)));
}
}

private static AddressAndPort parseHost(String value) {
HostAndPort hostAndPort = HostAndPort.fromString(value);
return new AddressAndPort(hostAndPort.getHost(), hostAndPort.hasPort() ? hostAndPort.getPort() : null);
}

private AddressAndPort parseAndCheckHost(Property property, String value) {
AddressAndPort addressAndPort = parseHost(value);
checkValidHosts(property, singleton(addressAndPort));
return addressAndPort;
}

private static NodeType toNodeType(Props props) {
String nodeTypeValue = requireValue(props, CLUSTER_NODE_TYPE.getKey());
String nodeTypeValue = requireValue(props, CLUSTER_NODE_TYPE);
if (!NodeType.isValid(nodeTypeValue)) {
throw new MessageException(format("Invalid value for property %s: [%s], only [%s] are allowed", CLUSTER_NODE_TYPE.getKey(), nodeTypeValue,
Arrays.stream(NodeType.values()).map(NodeType::getValue).collect(joining(", "))));
@@ -102,46 +152,59 @@ public class ClusterSettings implements Consumer<Props> {
return NodeType.parse(nodeTypeValue);
}

private static String requireValue(Props props, String key) {
private static String requireValue(Props props, Property property) {
String key = property.getKey();
String value = props.value(key);
if (isBlank(value)) {
String trimmedValue = value == null ? null : value.trim();
if (trimmedValue == null || trimmedValue.isEmpty()) {
throw new MessageException(format("Property %s is mandatory", key));
}
return value;
return trimmedValue;
}

private static void ensureNotH2(Props props) {
String jdbcUrl = props.value(JDBC_URL.getKey());
if (isBlank(jdbcUrl) || jdbcUrl.startsWith("jdbc:h2:")) {
String trimmedJdbcUrl = jdbcUrl == null ? null : jdbcUrl.trim();
if (trimmedJdbcUrl == null || trimmedJdbcUrl.isEmpty() || trimmedJdbcUrl.startsWith("jdbc:h2:")) {
throw new MessageException("Embedded database is not supported in cluster mode");
}
}

private void ensureNotLoopbackAddresses(Props props, String propertyKey) {
stream(requireValue(props, propertyKey).split(","))
.filter(StringUtils::isNotBlank)
.map(StringUtils::trim)
.map(s -> StringUtils.substringBefore(s, ":"))
.forEach(ip -> {
try {
if (network.isLoopbackInetAddress(network.toInetAddress(ip))) {
throw new MessageException(format("Property %s must not be a loopback address: %s", propertyKey, ip));
}
} catch (UnknownHostException e) {
throw new MessageException(format("Property %s must not a valid address: %s [%s]", propertyKey, ip, e.getMessage()));
}
});
}

private void ensureLocalButNotLoopbackAddress(Props props, String propertyKey) {
String propertyValue = props.nonNullValue(propertyKey).trim();
try {
InetAddress address = network.toInetAddress(propertyValue);
if (!network.isLocalInetAddress(address) || network.isLoopbackInetAddress(address)) {
throw new MessageException(format("Property %s must be a local non-loopback address: %s", propertyKey, propertyValue));
}
} catch (UnknownHostException | SocketException e) {
throw new MessageException(format("Property %s must be a local non-loopback address: %s [%s]", propertyKey, propertyValue, e.getMessage()));
private void ensureNotLoopbackAddresses(Property property, Set<AddressAndPort> hostAndPorts) {
Set<AddressAndPort> loopbackAddresses = hostAndPorts.stream()
.filter(t -> network.isLoopback(t.getHost()))
.collect(MoreCollectors.toSet());
if (!loopbackAddresses.isEmpty()) {
throw new MessageException(format("Property %s must not contain a loopback address: %s", property.getKey(),
loopbackAddresses.stream().map(AddressAndPort::getHost).sorted().collect(Collectors.joining(", "))));
}
}

private void ensureLocalButNotLoopbackAddress(Property property, AddressAndPort addressAndPort) {
String host = addressAndPort.getHost();
if (!network.isLocal(host) || network.isLoopback(host)) {
throw new MessageException(format("Property %s must be a local non-loopback address: %s", property.getKey(), addressAndPort.getHost()));
}
}

private static class AddressAndPort {
private static final int NO_PORT = -1;

/** the host from setting, can be a hostname or an IP address */
private final String host;
private final int port;

private AddressAndPort(String host, @Nullable Integer port) {
this.host = host;
this.port = port == null ? NO_PORT : port;
}

public String getHost() {
return host;
}

public boolean hasPort() {
return port != NO_PORT;
}
}


+ 1
- 1
server/sonar-main/src/test/java/org/sonar/application/cluster/ClusterAppStateImplTest.java Dosyayı Görüntüle

@@ -155,7 +155,7 @@ public class ClusterAppStateImplTest {
return new HazelcastMemberBuilder()
.setProcessId(ProcessId.COMPUTE_ENGINE)
.setNodeName("bar")
.setPort(NetworkUtilsImpl.INSTANCE.getNextAvailablePort(loopback))
.setPort(NetworkUtilsImpl.INSTANCE.getNextLoopbackAvailablePort())
.setNetworkInterface(loopback.getHostAddress())
.build();
}

+ 280
- 60
server/sonar-main/src/test/java/org/sonar/application/config/ClusterSettingsTest.java Dosyayı Görüntüle

@@ -19,18 +19,29 @@
*/
package org.sonar.application.config;

import com.tngtech.java.junit.dataprovider.DataProvider;
import com.tngtech.java.junit.dataprovider.DataProviderRunner;
import com.tngtech.java.junit.dataprovider.UseDataProvider;
import java.net.InetAddress;
import org.junit.Before;
import java.util.Arrays;
import java.util.Collection;
import java.util.Optional;
import java.util.stream.Stream;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.stubbing.Answer;
import org.sonar.process.MessageException;
import org.sonar.process.NetworkUtils;
import org.sonar.process.NetworkUtilsImpl;

import static com.google.common.collect.ImmutableList.of;
import static java.lang.String.format;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.spy;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.when;
import static org.sonar.process.ProcessId.COMPUTE_ENGINE;
import static org.sonar.process.ProcessId.ELASTICSEARCH;
@@ -43,23 +54,18 @@ import static org.sonar.process.ProcessProperties.Property.CLUSTER_SEARCH_HOSTS;
import static org.sonar.process.ProcessProperties.Property.JDBC_URL;
import static org.sonar.process.ProcessProperties.Property.SEARCH_HOST;

@RunWith(DataProviderRunner.class)
public class ClusterSettingsTest {

@Rule
public ExpectedException expectedException = ExpectedException.none();

private InetAddress nonLoopbackLocal = InetAddress.getLoopbackAddress();
private NetworkUtils network = spy(NetworkUtilsImpl.INSTANCE);

@Before
public void setUp() throws Exception {
when(network.isLocalInetAddress(nonLoopbackLocal)).thenReturn(true);
when(network.isLoopbackInetAddress(nonLoopbackLocal)).thenReturn(false);
}
private NetworkUtils network = Mockito.mock(NetworkUtils.class);

@Test
public void test_isClusterEnabled() {
TestAppSettings settings = newSettingsForAppNode().set(CLUSTER_ENABLED.getKey(), "true");
@UseDataProvider("validIPv4andIPv6Addresses")
public void test_isClusterEnabled(String host) {
TestAppSettings settings = newSettingsForAppNode(host).set(CLUSTER_ENABLED.getKey(), "true");
assertThat(ClusterSettings.isClusterEnabled(settings)).isTrue();

settings = new TestAppSettings().set(CLUSTER_ENABLED.getKey(), "false");
@@ -78,11 +84,12 @@ public class ClusterSettingsTest {
}

@Test
public void getEnabledProcesses_returns_configured_processes_in_cluster_mode() {
TestAppSettings settings = newSettingsForAppNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void getEnabledProcesses_returns_configured_processes_in_cluster_mode(String host) {
TestAppSettings settings = newSettingsForAppNode(host);
assertThat(ClusterSettings.getEnabledProcesses(settings)).containsOnly(COMPUTE_ENGINE, WEB_SERVER);

settings = newSettingsForSearchNode();
settings = newSettingsForSearchNode(host);
assertThat(ClusterSettings.getEnabledProcesses(settings)).containsOnly(ELASTICSEARCH);
}

@@ -110,8 +117,9 @@ public class ClusterSettingsTest {
}

@Test
public void accept_throws_MessageException_if_internal_property_for_startup_leader_is_configured() {
TestAppSettings settings = newSettingsForAppNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void accept_throws_MessageException_if_internal_property_for_startup_leader_is_configured(String host) {
TestAppSettings settings = newSettingsForAppNode(host);
settings.set("sonar.cluster.web.startupLeader", "true");

expectedException.expect(MessageException.class);
@@ -131,8 +139,9 @@ public class ClusterSettingsTest {
}

@Test
public void accept_throws_MessageException_if_h2_on_application_node() {
TestAppSettings settings = newSettingsForAppNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void accept_throws_MessageException_if_h2_on_application_node(String host) {
TestAppSettings settings = newSettingsForAppNode(host);
settings.set("sonar.jdbc.url", "jdbc:h2:mem");

expectedException.expect(MessageException.class);
@@ -142,8 +151,11 @@ public class ClusterSettingsTest {
}

@Test
public void accept_does_not_verify_h2_on_search_node() {
TestAppSettings settings = newSettingsForSearchNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void accept_does_not_verify_h2_on_search_node(String host) {
mockValidHost(host);
mockLocalNonLoopback(host);
TestAppSettings settings = newSettingsForSearchNode(host);
settings.set("sonar.jdbc.url", "jdbc:h2:mem");

// do not fail
@@ -151,8 +163,9 @@ public class ClusterSettingsTest {
}

@Test
public void accept_throws_MessageException_on_application_node_if_default_jdbc_url() {
TestAppSettings settings = newSettingsForAppNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void accept_throws_MessageException_on_application_node_if_default_jdbc_url(String host) {
TestAppSettings settings = newSettingsForAppNode(host);
settings.clearProperty(JDBC_URL.getKey());

expectedException.expect(MessageException.class);
@@ -168,82 +181,97 @@ public class ClusterSettingsTest {
}

@Test
public void isLocalElasticsearchEnabled_returns_true_on_search_node() {
TestAppSettings settings = newSettingsForSearchNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void isLocalElasticsearchEnabled_returns_true_on_search_node(String host) {
TestAppSettings settings = newSettingsForSearchNode(host);

assertThat(ClusterSettings.isLocalElasticsearchEnabled(settings)).isTrue();
}

@Test
public void shouldStartHazelcast_must_be_true_on_AppNode() {
TestAppSettings settings = newSettingsForAppNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void shouldStartHazelcast_must_be_true_on_AppNode(String host) {
TestAppSettings settings = newSettingsForAppNode(host);

assertThat(ClusterSettings.shouldStartHazelcast(settings)).isTrue();
}

@Test
public void shouldStartHazelcast_must_be_false_on_SearchNode() {
TestAppSettings settings = newSettingsForSearchNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void shouldStartHazelcast_must_be_false_on_SearchNode(String host) {
TestAppSettings settings = newSettingsForSearchNode(host);

assertThat(ClusterSettings.shouldStartHazelcast(settings)).isFalse();
}

@Test
public void shouldStartHazelcast_must_be_false_when_cluster_not_activated() {
TestAppSettings settings = newSettingsForSearchNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void shouldStartHazelcast_must_be_false_when_cluster_not_activated(String host) {
TestAppSettings settings = newSettingsForSearchNode(host);
settings.set(CLUSTER_ENABLED.getKey(), "false");
assertThat(ClusterSettings.shouldStartHazelcast(settings)).isFalse();

settings = newSettingsForAppNode();
settings = newSettingsForAppNode(host);
settings.set(CLUSTER_ENABLED.getKey(), "false");
assertThat(ClusterSettings.shouldStartHazelcast(settings)).isFalse();
}

@Test
public void isLocalElasticsearchEnabled_returns_true_for_a_application_node() {
TestAppSettings settings = newSettingsForAppNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void isLocalElasticsearchEnabled_returns_true_for_a_application_node(String host) {
TestAppSettings settings = newSettingsForAppNode(host);

assertThat(ClusterSettings.isLocalElasticsearchEnabled(settings)).isFalse();
}

@Test
public void accept_throws_MessageException_if_searchHost_is_missing() {
TestAppSettings settings = newSettingsForSearchNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void accept_throws_MessageException_if_searchHost_is_missing(String host) {
TestAppSettings settings = newSettingsForSearchNode(host);
settings.clearProperty(SEARCH_HOST.getKey());
assertThatPropertyIsMandatory(settings, SEARCH_HOST.getKey());
}

@Test
public void accept_throws_MessageException_if_searchHost_is_empty() {
TestAppSettings settings = newSettingsForSearchNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void accept_throws_MessageException_if_searchHost_is_empty(String host) {
TestAppSettings settings = newSettingsForSearchNode(host);
settings.set(SEARCH_HOST.getKey(), "");
assertThatPropertyIsMandatory(settings, SEARCH_HOST.getKey());
}

@Test
public void accept_throws_MessageException_on_app_node_if_clusterHosts_is_missing() {
TestAppSettings settings = newSettingsForAppNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void accept_throws_MessageException_on_app_node_if_clusterHosts_is_missing(String host) {
TestAppSettings settings = newSettingsForAppNode(host);
settings.clearProperty(CLUSTER_HZ_HOSTS.getKey());
assertThatPropertyIsMandatory(settings, CLUSTER_HZ_HOSTS.getKey());
}

@Test
public void accept_throws_MessageException_if_clusterSearchHosts_is_missing() {
TestAppSettings settings = newSettingsForSearchNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void accept_throws_MessageException_if_clusterSearchHosts_is_missing(String host) {
mockValidHost(host);
mockLocalNonLoopback(host);
TestAppSettings settings = newSettingsForSearchNode(host);
settings.clearProperty(CLUSTER_SEARCH_HOSTS.getKey());
assertThatPropertyIsMandatory(settings, CLUSTER_SEARCH_HOSTS.getKey());
}

@Test
public void accept_throws_MessageException_if_clusterSearchHosts_is_empty() {
TestAppSettings settings = newSettingsForSearchNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void accept_throws_MessageException_if_clusterSearchHosts_is_empty(String host) {
mockValidHost(host);
mockLocalNonLoopback(host);
TestAppSettings settings = newSettingsForSearchNode(host);
settings.set(CLUSTER_SEARCH_HOSTS.getKey(), "");
assertThatPropertyIsMandatory(settings, CLUSTER_SEARCH_HOSTS.getKey());
}

@Test
public void accept_throws_MessageException_if_jwt_token_is_not_set_on_application_nodes() {
TestAppSettings settings = newSettingsForAppNode();
@UseDataProvider("validIPv4andIPv6Addresses")
public void accept_throws_MessageException_if_jwt_token_is_not_set_on_application_nodes(String host) {
TestAppSettings settings = newSettingsForAppNode(host);
settings.clearProperty("sonar.auth.jwtBase64Hs256Secret");
assertThatPropertyIsMandatory(settings, "sonar.auth.jwtBase64Hs256Secret");
}
@@ -255,14 +283,205 @@ public class ClusterSettingsTest {
}

@Test
public void shouldStartHazelcast_should_return_false_on_SearchNode() {
assertThat(ClusterSettings.shouldStartHazelcast(newSettingsForSearchNode())).isFalse();
@UseDataProvider("validIPv4andIPv6Addresses")
public void shouldStartHazelcast_should_return_false_on_SearchNode(String host) {
assertThat(ClusterSettings.shouldStartHazelcast(newSettingsForSearchNode(host))).isFalse();
}

@Test
@UseDataProvider("validIPv4andIPv6Addresses")
public void shouldStartHazelcast_should_return_true_on_AppNode(String host) {
assertThat(ClusterSettings.shouldStartHazelcast(newSettingsForAppNode(host))).isTrue();
}

@Test
public void shouldStartHazelcast_should_return_true_on_AppNode() {
assertThat(ClusterSettings.shouldStartHazelcast(newSettingsForAppNode())).isTrue();
public void validate_host_in_any_cluster_property_of_APP_node() {
TestAppSettings settings = new TestAppSettings()
.set(CLUSTER_ENABLED.getKey(), "true")
.set(CLUSTER_NODE_TYPE.getKey(), "application")
.set(CLUSTER_NODE_HOST.getKey(), "hz_host")
.set(CLUSTER_HZ_HOSTS.getKey(), "remote_hz_host_1,remote_hz_host_2")
.set(CLUSTER_SEARCH_HOSTS.getKey(), "remote_search_host_1:9001, remote_search_host_2:9001")
.set(JDBC_URL.getKey(), "jdbc:postgresql://localhost/sonar")
.set("sonar.auth.jwtBase64Hs256Secret", "abcde");

verifyHostIsChecked(settings, of("hz_host"), "Address in property sonar.cluster.node.host is not a valid address: hz_host");
verifyHostIsChecked(settings, of("remote_hz_host_1"), "Address in property sonar.cluster.hosts is not a valid address: remote_hz_host_1");
verifyHostIsChecked(settings, of("remote_hz_host_2"), "Address in property sonar.cluster.hosts is not a valid address: remote_hz_host_2");
verifyHostIsChecked(settings,
of("remote_hz_host_1", "remote_hz_host_2"),
"Address in property sonar.cluster.hosts is not a valid address: remote_hz_host_1, remote_hz_host_2");
verifyHostIsChecked(settings, of("remote_search_host_1"), "Address in property sonar.cluster.search.hosts is not a valid address: remote_search_host_1");
verifyHostIsChecked(settings, of("remote_search_host_2"), "Address in property sonar.cluster.search.hosts is not a valid address: remote_search_host_2");
verifyHostIsChecked(settings,
of("remote_search_host_1", "remote_search_host_2"),
"Address in property sonar.cluster.search.hosts is not a valid address: remote_search_host_1, remote_search_host_2");
}

@Test
public void validate_host_resolved_in_any_cluster_property_of_SEARCH_node() {
TestAppSettings settings = new TestAppSettings()
.set(CLUSTER_ENABLED.getKey(), "true")
.set(CLUSTER_NODE_TYPE.getKey(), "search")
.set(CLUSTER_NODE_HOST.getKey(), "hz_host")
.set(CLUSTER_SEARCH_HOSTS.getKey(), "remote_search_host_1:9001, remote_search_host_2:9001")
.set(SEARCH_HOST.getKey(), "search_host");

verifyHostIsChecked(settings, of("hz_host"), "Address in property sonar.cluster.node.host is not a valid address: hz_host");
verifyHostIsChecked(settings, of("remote_search_host_1"), "Address in property sonar.cluster.search.hosts is not a valid address: remote_search_host_1");
verifyHostIsChecked(settings, of("remote_search_host_2"), "Address in property sonar.cluster.search.hosts is not a valid address: remote_search_host_2");
verifyHostIsChecked(settings, of("search_host"), "Address in property sonar.search.host is not a valid address: search_host");
}

private void verifyHostIsChecked(TestAppSettings settings, Collection<String> invalidHosts, String expectedMessage) {
reset(network);
mockAllHostsValidBut(invalidHosts);
mockLocalNonLoopback("hz_host", "search_host");
assertThatThrownBy(() -> new ClusterSettings(network).accept(settings.getProps()))
.isInstanceOf(MessageException.class)
.hasMessage(expectedMessage);
}

@Test
public void ensure_no_loopback_host_in_properties_of_APP_node() {
TestAppSettings settings = new TestAppSettings()
.set(CLUSTER_ENABLED.getKey(), "true")
.set(CLUSTER_NODE_TYPE.getKey(), "application")
.set(CLUSTER_NODE_HOST.getKey(), "hz_host")
.set(CLUSTER_HZ_HOSTS.getKey(), "remote_hz_host_1,remote_hz_host_2")
.set(CLUSTER_SEARCH_HOSTS.getKey(), "remote_search_host_1:9001, remote_search_host_2:9001")
.set(JDBC_URL.getKey(), "jdbc:postgresql://localhost/sonar")
.set("sonar.auth.jwtBase64Hs256Secret", "abcde");

verifyLoopbackChecked(settings, of("hz_host"), "Property sonar.cluster.node.host must be a local non-loopback address: hz_host");
verifyLoopbackChecked(settings, of("remote_search_host_1"), "Property sonar.cluster.search.hosts must not contain a loopback address: remote_search_host_1");
verifyLoopbackChecked(settings, of("remote_search_host_2"), "Property sonar.cluster.search.hosts must not contain a loopback address: remote_search_host_2");
verifyLoopbackChecked(settings,
of("remote_search_host_1", "remote_search_host_2"),
"Property sonar.cluster.search.hosts must not contain a loopback address: remote_search_host_1, remote_search_host_2");
verifyLoopbackChecked(settings, of("remote_hz_host_1"), "Property sonar.cluster.hosts must not contain a loopback address: remote_hz_host_1");
verifyLoopbackChecked(settings, of("remote_hz_host_2"), "Property sonar.cluster.hosts must not contain a loopback address: remote_hz_host_2");
verifyLoopbackChecked(settings,
of("remote_hz_host_1", "remote_hz_host_2"),
"Property sonar.cluster.hosts must not contain a loopback address: remote_hz_host_1, remote_hz_host_2");
}

@Test
public void ensure_no_loopback_host_in_properties_of_SEARCH_node() {
TestAppSettings settings = new TestAppSettings()
.set(CLUSTER_ENABLED.getKey(), "true")
.set(CLUSTER_NODE_TYPE.getKey(), "search")
.set(CLUSTER_NODE_HOST.getKey(), "hz_host")
.set(CLUSTER_SEARCH_HOSTS.getKey(), "remote_search_host_1:9001, remote_search_host_2:9001")
.set(SEARCH_HOST.getKey(), "search_host");

verifyLoopbackChecked(settings, of("hz_host"), "Property sonar.cluster.node.host must be a local non-loopback address: hz_host");
verifyLoopbackChecked(settings, of("search_host"), "Property sonar.search.host must be a local non-loopback address: search_host");
verifyLoopbackChecked(settings, of("remote_search_host_1"), "Property sonar.cluster.search.hosts must not contain a loopback address: remote_search_host_1");
verifyLoopbackChecked(settings, of("remote_search_host_2"), "Property sonar.cluster.search.hosts must not contain a loopback address: remote_search_host_2");
verifyLoopbackChecked(settings,
of("remote_search_host_1", "remote_search_host_2"),
"Property sonar.cluster.search.hosts must not contain a loopback address: remote_search_host_1, remote_search_host_2");
}

private void verifyLoopbackChecked(TestAppSettings settings, Collection<String> hosts, String expectedMessage) {
reset(network);
mockAllHostsValid();
mockLocalNonLoopback("hz_host", "search_host");
// will overwrite above move if necessary
hosts.forEach(this::mockLoopback);
assertThatThrownBy(() -> new ClusterSettings(network).accept(settings.getProps()))
.isInstanceOf(MessageException.class)
.hasMessage(expectedMessage);
}

@Test
public void ensure_HZ_HOST_is_local_non_loopback_in_properties_of_APP_node() {
TestAppSettings settings = new TestAppSettings()
.set(CLUSTER_ENABLED.getKey(), "true")
.set(CLUSTER_NODE_TYPE.getKey(), "application")
.set(CLUSTER_NODE_HOST.getKey(), "hz_host")
.set(CLUSTER_HZ_HOSTS.getKey(), "remote_hz_host_1,remote_hz_host_2")
.set(CLUSTER_SEARCH_HOSTS.getKey(), "remote_search_host_1:9001, remote_search_host_2:9001")
.set(JDBC_URL.getKey(), "jdbc:postgresql://localhost/sonar")
.set("sonar.auth.jwtBase64Hs256Secret", "abcde");

verifyLocalChecked(settings, "hz_host", "Property sonar.cluster.node.host must be a local non-loopback address: hz_host");
}

@Test
public void ensure_HZ_HOST_and_SEARCH_HOST_are_local_non_loopback_in_properties_of_SEARCH_node() {
TestAppSettings settings = new TestAppSettings()
.set(CLUSTER_ENABLED.getKey(), "true")
.set(CLUSTER_NODE_TYPE.getKey(), "search")
.set(CLUSTER_NODE_HOST.getKey(), "hz_host")
.set(CLUSTER_SEARCH_HOSTS.getKey(), "remote_search_host_1:9001, remote_search_host_2:9001")
.set(SEARCH_HOST.getKey(), "search_host");

verifyLocalChecked(settings, "hz_host", "Property sonar.cluster.node.host must be a local non-loopback address: hz_host");
verifyLocalChecked(settings, "search_host", "Property sonar.search.host must be a local non-loopback address: search_host");
}

private void verifyLocalChecked(TestAppSettings settings, String host, String expectedMessage) {
reset(network);
mockAllHostsValid();
mockLocalNonLoopback("hz_host", "search_host");
// will overwrite above move if necessary
mockAllNonLoopback();
mockNonLocal(host);
assertThatThrownBy(() -> new ClusterSettings(network).accept(settings.getProps()))
.isInstanceOf(MessageException.class)
.hasMessage(expectedMessage);
}

private void mockAllNonLoopback() {
when(network.isLoopback(anyString())).thenReturn(false);
}

private void mockNonLocal(String search_host) {
when(network.isLocal(search_host)).thenReturn(false);
}

private void mockLoopback(String host) {
when(network.isLoopback(host)).thenReturn(true);
}

private void mockValidHost(String host) {
String unbracketedHost = host.startsWith("[") ? host.substring(1, host.length() - 1) : host;
when(network.toInetAddress(unbracketedHost)).thenReturn(Optional.of(InetAddress.getLoopbackAddress()));
}

public void mockAllHostsValid() {
when(network.toInetAddress(anyString())).thenReturn(Optional.of(InetAddress.getLoopbackAddress()));
}

public void mockAllHostsValidBut(Collection<String> hosts) {
when(network.toInetAddress(anyString()))
.thenAnswer((Answer<Optional<InetAddress>>) invocation -> {
Object arg = invocation.getArgument(0);
if (hosts.contains(arg)) {
return Optional.empty();
}
return Optional.of(InetAddress.getLoopbackAddress());
});
}

private void mockLocalNonLoopback(String host, String... otherhosts) {
Stream.concat(Stream.of(host), Arrays.stream(otherhosts))
.forEach(h -> {
String unbracketedHost = h.startsWith("[") ? h.substring(1, h.length() - 1) : h;
when(network.isLocal(unbracketedHost)).thenReturn(true);
when(network.isLoopback(unbracketedHost)).thenReturn(false);
});

}

@DataProvider
public static Object[][] validIPv4andIPv6Addresses() {
return new Object[][] {
{"10.150.0.188"},
{"[fe80::fde2:607e:ae56:e636]"},
};
}

private void assertThatPropertyIsMandatory(TestAppSettings settings, String key) {
@@ -272,24 +491,25 @@ public class ClusterSettingsTest {
new ClusterSettings(network).accept(settings.getProps());
}

private TestAppSettings newSettingsForAppNode() {
private TestAppSettings newSettingsForAppNode(String host) {
return new TestAppSettings()
.set(CLUSTER_ENABLED.getKey(), "true")
.set(CLUSTER_NODE_TYPE.getKey(), "application")
.set(CLUSTER_NODE_HOST.getKey(), nonLoopbackLocal.getHostAddress())
.set(CLUSTER_HZ_HOSTS.getKey(), nonLoopbackLocal.getHostAddress())
.set(CLUSTER_SEARCH_HOSTS.getKey(), nonLoopbackLocal.getHostAddress())
.set(CLUSTER_NODE_HOST.getKey(), host)
.set(CLUSTER_HZ_HOSTS.getKey(), host)
.set(CLUSTER_SEARCH_HOSTS.getKey(), host + ":9001")
.set("sonar.auth.jwtBase64Hs256Secret", "abcde")
.set(JDBC_URL.getKey(), "jdbc:postgresql://localhost/sonar");
}

private TestAppSettings newSettingsForSearchNode() {
private TestAppSettings newSettingsForSearchNode(String host) {
return new TestAppSettings()
.set(CLUSTER_ENABLED.getKey(), "true")
.set(CLUSTER_NODE_TYPE.getKey(), "search")
.set(CLUSTER_NODE_HOST.getKey(), nonLoopbackLocal.getHostAddress())
.set(CLUSTER_HZ_HOSTS.getKey(), nonLoopbackLocal.getHostAddress())
.set(CLUSTER_SEARCH_HOSTS.getKey(), nonLoopbackLocal.getHostAddress())
.set(SEARCH_HOST.getKey(), nonLoopbackLocal.getHostAddress());
.set(CLUSTER_NODE_HOST.getKey(), host)
.set(CLUSTER_HZ_HOSTS.getKey(), host)
.set(CLUSTER_SEARCH_HOSTS.getKey(), host + ":9001")
.set(SEARCH_HOST.getKey(), host);
}

}

+ 7
- 6
server/sonar-process/src/main/java/org/sonar/process/NetworkUtils.java Dosyayı Görüntüle

@@ -21,14 +21,15 @@ package org.sonar.process;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.function.Predicate;

public interface NetworkUtils {

int getNextAvailablePort(InetAddress address);
int getNextLoopbackAvailablePort();

OptionalInt getNextAvailablePort(String hostOrAddress);

/**
* Identifying the localhost machine
@@ -44,11 +45,11 @@ public interface NetworkUtils {
* If text value references an IPv4 or IPv6 address, then DNS is
* not used.
*/
InetAddress toInetAddress(String hostOrAddress) throws UnknownHostException;
Optional<InetAddress> toInetAddress(String hostOrAddress);

boolean isLocalInetAddress(InetAddress address) throws SocketException;
boolean isLocal(String hostOrAddress);

boolean isLoopbackInetAddress(InetAddress address);
boolean isLoopback(String hostOrAddress);

/**
* Returns the machine {@link InetAddress} that matches the specified

+ 45
- 16
server/sonar-process/src/main/java/org/sonar/process/NetworkUtilsImpl.java Dosyayı Görüntüle

@@ -30,22 +30,36 @@ import java.net.UnknownHostException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.Set;
import java.util.function.Predicate;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;

import static java.lang.String.format;

public class NetworkUtilsImpl implements NetworkUtils {

public static final NetworkUtils INSTANCE = new NetworkUtilsImpl();
private static final Set<Integer> PORTS_ALREADY_ALLOCATED = new HashSet<>();
private static final int PORT_MAX_TRIES = 50;
private static final Logger LOG = Loggers.get(NetworkUtilsImpl.class);

public static final NetworkUtils INSTANCE = new NetworkUtilsImpl();

NetworkUtilsImpl() {
// prevent instantiation
}

@Override
public int getNextAvailablePort(InetAddress address) {
return getNextAvailablePort(address, PortAllocator.INSTANCE);
public int getNextLoopbackAvailablePort() {
return getNextAvailablePort(InetAddress.getLoopbackAddress(), PortAllocator.INSTANCE);
}

@Override
public OptionalInt getNextAvailablePort(String hostOrAddress) {
return OptionalInt.of(toInetAddress(hostOrAddress)
.map(t -> getNextAvailablePort(t, PortAllocator.INSTANCE))
.orElseThrow(() -> new IllegalArgumentException(format("Can not resolve address %s", hostOrAddress))));
}

/**
@@ -84,32 +98,46 @@ public class NetworkUtilsImpl implements NetworkUtils {

@Override
public String getHostname() {
String hostname;
try {
hostname = InetAddress.getLocalHost().getHostName();
return InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e) {
hostname = "unresolved hostname";
LOG.trace("Failed to get hostname", e);
return "unresolved hostname";
}

return hostname;
}

@Override
public InetAddress toInetAddress(String hostOrAddress) throws UnknownHostException {
if (InetAddresses.isInetAddress(hostOrAddress)) {
return InetAddresses.forString(hostOrAddress);
public Optional<InetAddress> toInetAddress(String hostOrAddress) {
try {
if (InetAddresses.isInetAddress(hostOrAddress)) {
return Optional.of(InetAddresses.forString(hostOrAddress));
}
return Optional.of(InetAddress.getByName(hostOrAddress));
} catch (UnknownHostException e) {
LOG.trace("toInetAddress({}) failed", hostOrAddress, e);
return Optional.empty();
}
return InetAddress.getByName(hostOrAddress);
}

@Override
public boolean isLocalInetAddress(InetAddress address) throws SocketException {
return NetworkInterface.getByInetAddress(address) != null ;
public boolean isLocal(String hostOrAddress) {
try {
Optional<InetAddress> inetAddress = toInetAddress(hostOrAddress);
if (inetAddress.isPresent()) {
return NetworkInterface.getByInetAddress(inetAddress.get()) != null;
}
return false;
} catch (SocketException e) {
LOG.trace("isLocalInetAddress({}) failed", hostOrAddress, e);
return false;
}
}

@Override
public boolean isLoopbackInetAddress(InetAddress address) {
return address.isLoopbackAddress();
public boolean isLoopback(String hostOrAddress) {
return toInetAddress(hostOrAddress)
.filter(InetAddress::isLoopbackAddress)
.isPresent();
}

@Override
@@ -121,6 +149,7 @@ public class NetworkUtilsImpl implements NetworkUtils {
.filter(predicate)
.findFirst();
} catch (SocketException e) {
LOG.trace("getLocalInetAddress(Predicate<InetAddress>) failed", e);
throw new IllegalStateException("Can not retrieve network interfaces", e);
}
}

+ 4
- 8
server/sonar-process/src/main/java/org/sonar/process/ProcessProperties.java Dosyayı Görüntüle

@@ -20,7 +20,6 @@
package org.sonar.process;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@@ -33,9 +32,8 @@ import javax.annotation.Nullable;
import org.sonar.core.extension.CoreExtension;
import org.sonar.core.extension.ServiceLoaderWrapper;

import static java.lang.String.format;

import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;

/**
* Constants shared by search, web server and app processes.
@@ -200,11 +198,9 @@ public class ProcessProperties {
String port = props.value(portPropertyKey);
if ("0".equals(port)) {
String address = props.nonNullValue(addressPropertyKey);
try {
props.set(portPropertyKey, String.valueOf(NetworkUtilsImpl.INSTANCE.getNextAvailablePort(InetAddress.getByName(address))));
} catch (UnknownHostException e) {
throw new IllegalStateException("Cannot resolve address [" + address + "] set by property [" + addressPropertyKey + "]", e);
}
int allocatedPort = NetworkUtilsImpl.INSTANCE.getNextAvailablePort(address)
.orElseThrow(() -> new IllegalStateException("Cannot resolve address [" + address + "] set by property [" + addressPropertyKey + "]"));
props.set(portPropertyKey, String.valueOf(allocatedPort));
}
}


+ 70
- 11
server/sonar-process/src/test/java/org/sonar/process/NetworkUtilsImplTest.java Dosyayı Görüntüle

@@ -21,6 +21,7 @@ package org.sonar.process;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Optional;
@@ -30,6 +31,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assume.assumeThat;

@@ -42,7 +44,8 @@ public class NetworkUtilsImplTest {

@Test
public void getNextAvailablePort_returns_a_port() throws Exception {
int port = underTest.getNextAvailablePort(InetAddress.getLocalHost());
String localhost = InetAddress.getLocalHost().getHostName();
int port = underTest.getNextAvailablePort(localhost).getAsInt();
assertThat(port)
.isGreaterThan(1_023)
.isLessThanOrEqualTo(65_535);
@@ -50,10 +53,11 @@ public class NetworkUtilsImplTest {

@Test
public void getNextAvailablePort_does_not_return_twice_the_same_port() throws Exception {
String localhost = InetAddress.getLocalHost().getHostName();
Set<Integer> ports = new HashSet<>(Arrays.asList(
underTest.getNextAvailablePort(InetAddress.getLocalHost()),
underTest.getNextAvailablePort(InetAddress.getLocalHost()),
underTest.getNextAvailablePort(InetAddress.getLocalHost())));
underTest.getNextAvailablePort(localhost).getAsInt(),
underTest.getNextAvailablePort(localhost).getAsInt(),
underTest.getNextAvailablePort(localhost).getAsInt()));
assertThat(ports).hasSize(3);
}

@@ -68,6 +72,17 @@ public class NetworkUtilsImplTest {
assertThat(address.get().isLoopbackAddress()).isFalse();
}

@Test
public void getHostname_returns_hostname_of_localhost_otherwise_a_constant() {
try {
InetAddress localHost = InetAddress.getLocalHost();
assertThat(underTest.getHostname()).isEqualTo(localHost.getHostName());
} catch (UnknownHostException e) {
// no localhost on host running the UT
assertThat(underTest.getHostname()).isEqualTo("unresolved hostname");
}
}

@Test
public void getLocalInetAddress_filters_local_addresses() {
InetAddress address = underTest.getLocalInetAddress(InetAddress::isLoopbackAddress).get();
@@ -81,20 +96,64 @@ public class NetworkUtilsImplTest {
}

@Test
public void toInetAddress_supports_host_names() throws Exception {
assertThat(underTest.toInetAddress("localhost")).isNotNull();
public void toInetAddress_supports_host_names() {
assertThat(underTest.toInetAddress("localhost")).isNotEmpty();
// do not test values that require DNS calls. Build must support offline mode.
}

@Test
public void toInetAddress_supports_ipv4() throws Exception {
assertThat(underTest.toInetAddress("1.2.3.4")).isNotNull();
public void toInetAddress_supports_ipv4() {
assertThat(underTest.toInetAddress("1.2.3.4")).isNotEmpty();
}

@Test
public void toInetAddress_supports_ipv6() {
assertThat(underTest.toInetAddress("2a01:e34:ef1f:dbb0:c2f6:a978:c5c0:9ccb")).isNotEmpty();
assertThat(underTest.toInetAddress("[2a01:e34:ef1f:dbb0:c2f6:a978:c5c0:9ccb]")).isNotEmpty();
}

@Test
public void toInetAddress_supports_ipv6() throws Exception {
assertThat(underTest.toInetAddress("2a01:e34:ef1f:dbb0:c2f6:a978:c5c0:9ccb")).isNotNull();
assertThat(underTest.toInetAddress("[2a01:e34:ef1f:dbb0:c2f6:a978:c5c0:9ccb]")).isNotNull();
public void toInetAddress_returns_empty_on_unvalid_IP_and_hostname() {
assertThat(underTest.toInetAddress(randomAlphabetic(32))).isEmpty();
}

@Test
public void isLoopback_returns_true_on_loopback_address_or_host() {
InetAddress loopback = InetAddress.getLoopbackAddress();

assertThat(underTest.isLoopback(loopback.getHostAddress())).isTrue();
assertThat(underTest.isLoopback(loopback.getHostName())).isTrue();
}

@Test
public void isLoopback_returns_true_on_localhost_address_or_host_if_loopback() {
try {
InetAddress localHost = InetAddress.getLocalHost();
boolean isLoopback = localHost.isLoopbackAddress();
assertThat(underTest.isLoopback(localHost.getHostAddress())).isEqualTo(isLoopback);
assertThat(underTest.isLoopback(localHost.getHostName())).isEqualTo(isLoopback);
} catch (UnknownHostException e) {
// ignore, host running the test has no localhost
}
}

@Test
public void isLocal_returns_true_on_loopback_address_or_host() {
InetAddress loopback = InetAddress.getLoopbackAddress();

assertThat(underTest.isLocal(loopback.getHostAddress())).isTrue();
assertThat(underTest.isLocal(loopback.getHostName())).isTrue();
}

@Test
public void isLocal_returns_true_on_localhost_address_or_host() {
try {
InetAddress localHost = InetAddress.getLocalHost();

assertThat(underTest.isLocal(localHost.getHostAddress())).isTrue();
assertThat(underTest.isLocal(localHost.getHostName())).isTrue();
} catch (UnknownHostException e) {
// ignore, host running the test has no localhost
}
}
}

+ 1
- 1
server/sonar-process/src/test/java/org/sonar/process/cluster/hz/HazelcastMemberBuilderTest.java Dosyayı Görüntüle

@@ -49,7 +49,7 @@ public class HazelcastMemberBuilderTest {
HazelcastMember member = underTest
.setProcessId(ProcessId.COMPUTE_ENGINE)
.setNodeName("bar")
.setPort(NetworkUtilsImpl.INSTANCE.getNextAvailablePort(loopback))
.setPort(NetworkUtilsImpl.INSTANCE.getNextLoopbackAvailablePort())
.setNetworkInterface(loopback.getHostAddress())
.build();


+ 3
- 3
server/sonar-process/src/test/java/org/sonar/process/cluster/hz/HazelcastMemberImplTest.java Dosyayı Görüntüle

@@ -55,9 +55,9 @@ public class HazelcastMemberImplTest {

@BeforeClass
public static void setUp() {
int port1 = NetworkUtilsImpl.INSTANCE.getNextAvailablePort(loopback);
int port2 = NetworkUtilsImpl.INSTANCE.getNextAvailablePort(loopback);
int port3 = NetworkUtilsImpl.INSTANCE.getNextAvailablePort(loopback);
int port1 = NetworkUtilsImpl.INSTANCE.getNextLoopbackAvailablePort();
int port2 = NetworkUtilsImpl.INSTANCE.getNextLoopbackAvailablePort();
int port3 = NetworkUtilsImpl.INSTANCE.getNextLoopbackAvailablePort();
member1 = newHzMember(port1, port2, port3);
member2 = newHzMember(port2, port1, port3);
member3 = newHzMember(port3, port1, port2);

+ 3
- 3
server/sonar-webserver-core/src/test/java/org/sonar/server/platform/db/EmbeddedDatabaseTest.java Dosyayı Görüntüle

@@ -111,7 +111,7 @@ public class EmbeddedDatabaseTest {

@Test
public void start_ignores_URL_to_create_database_and_uses_empty_username_and_password_when_then_are_not_set() throws IOException {
int port = NetworkUtilsImpl.INSTANCE.getNextAvailablePort(InetAddress.getLoopbackAddress());
int port = NetworkUtilsImpl.INSTANCE.getNextLoopbackAvailablePort();
settings
.setProperty(PATH_DATA.getKey(), temporaryFolder.newFolder().getAbsolutePath())
.setProperty(JDBC_URL.getKey(), "jdbc url")
@@ -124,7 +124,7 @@ public class EmbeddedDatabaseTest {

@Test
public void start_creates_db_and_adds_tcp_listener() throws IOException {
int port = NetworkUtilsImpl.INSTANCE.getNextAvailablePort(InetAddress.getLoopbackAddress());
int port = NetworkUtilsImpl.INSTANCE.getNextLoopbackAvailablePort();
settings
.setProperty(PATH_DATA.getKey(), temporaryFolder.newFolder().getAbsolutePath())
.setProperty(JDBC_URL.getKey(), "jdbc url")
@@ -142,7 +142,7 @@ public class EmbeddedDatabaseTest {

@Test
public void start_supports_in_memory_H2_JDBC_URL() throws IOException {
int port = NetworkUtilsImpl.INSTANCE.getNextAvailablePort(InetAddress.getLoopbackAddress());
int port = NetworkUtilsImpl.INSTANCE.getNextLoopbackAvailablePort();
settings
.setProperty(PATH_DATA.getKey(), temporaryFolder.newFolder().getAbsolutePath())
.setProperty(JDBC_URL.getKey(), "jdbc:h2:mem:sonar")

+ 1
- 1
server/sonar-webserver/src/test/java/org/sonar/server/app/EmbeddedTomcatTest.java Dosyayı Görüntüle

@@ -55,7 +55,7 @@ public class EmbeddedTomcatTest {

// start server on a random port
InetAddress address = InetAddress.getLoopbackAddress();
int httpPort = NetworkUtilsImpl.INSTANCE.getNextAvailablePort(address);
int httpPort = NetworkUtilsImpl.INSTANCE.getNextLoopbackAvailablePort();
props.set("sonar.web.host", address.getHostAddress());
props.set("sonar.web.port", String.valueOf(httpPort));
EmbeddedTomcat tomcat = new EmbeddedTomcat(props);

Loading…
İptal
Kaydet