/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.elasticsearch.discovery.single; import org.apache.lucene.util.IOUtils; import org.elasticsearch.Version; import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.discovery.zen.PingContextProvider; import org.elasticsearch.discovery.zen.UnicastHostsProvider; import org.elasticsearch.discovery.zen.UnicastZenPing; import org.elasticsearch.discovery.zen.ZenPing; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.InternalTestCluster; import org.elasticsearch.test.NodeConfigurationSource; import org.elasticsearch.test.transport.MockTransportService; import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.transport.MockTcpTransportPlugin; import org.elasticsearch.transport.TransportService; import java.io.Closeable; import java.io.IOException; import java.util.Collections; import java.util.Stack; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CountDownLatch; import java.util.function.Function; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.not; @ESIntegTestCase.ClusterScope( scope = ESIntegTestCase.Scope.TEST, numDataNodes = 1, numClientNodes = 0, supportsDedicatedMasters = false, autoMinMasterNodes = false) public class SingleNodeDiscoveryIT extends ESIntegTestCase { @Override protected Settings nodeSettings(int nodeOrdinal) { return Settings .builder() .put(super.nodeSettings(nodeOrdinal)) .put("discovery.type", "single-node") .put("transport.tcp.port", "0") .build(); } public void testDoesNotRespondToZenPings() throws Exception { final Settings settings = Settings.builder().put("cluster.name", internalCluster().getClusterName()).build(); final Version version = Version.CURRENT; final Stack<Closeable> closeables = new Stack<>(); final TestThreadPool threadPool = new TestThreadPool(getClass().getName()); try { final MockTransportService pingTransport = MockTransportService.createNewService(settings, version, threadPool, null); pingTransport.start(); closeables.push(pingTransport); final TransportService nodeTransport = internalCluster().getInstance(TransportService.class); // try to ping the single node directly final UnicastHostsProvider provider = () -> Collections.singletonList(nodeTransport.getLocalNode()); final CountDownLatch latch = new CountDownLatch(1); final DiscoveryNodes nodes = DiscoveryNodes.builder() .add(nodeTransport.getLocalNode()) .add(pingTransport.getLocalNode()) .localNodeId(pingTransport.getLocalNode().getId()) .build(); final ClusterName clusterName = new ClusterName(internalCluster().getClusterName()); final ClusterState state = ClusterState.builder(clusterName).nodes(nodes).build(); final UnicastZenPing unicastZenPing = new UnicastZenPing(settings, threadPool, pingTransport, provider, () -> state) { @Override protected void finishPingingRound(PingingRound pingingRound) { latch.countDown(); super.finishPingingRound(pingingRound); } }; unicastZenPing.start(); closeables.push(unicastZenPing); final CompletableFuture<ZenPing.PingCollection> responses = new CompletableFuture<>(); unicastZenPing.ping(responses::complete, TimeValue.timeValueSeconds(3)); latch.await(); responses.get(); assertThat(responses.get().size(), equalTo(0)); } finally { while (!closeables.isEmpty()) { IOUtils.closeWhileHandlingException(closeables.pop()); } terminate(threadPool); } } public void testSingleNodesDoNotDiscoverEachOther() throws IOException, InterruptedException { final TransportService service = internalCluster().getInstance(TransportService.class); final int port = service.boundAddress().publishAddress().getPort(); final NodeConfigurationSource configurationSource = new NodeConfigurationSource() { @Override public Settings nodeSettings(int nodeOrdinal) { return Settings .builder() .put("discovery.type", "single-node") .put("http.enabled", false) .put("transport.type", "mock-socket-network") /* * We align the port ranges of the two as then with zen discovery these two * nodes would find each other. */ .put("transport.tcp.port", port + "-" + (port + 5 - 1)) .build(); } }; try (InternalTestCluster other = new InternalTestCluster( randomLong(), createTempDir(), false, false, 1, 1, internalCluster().getClusterName(), configurationSource, 0, false, "other", Collections.singletonList(MockTcpTransportPlugin.class), Function.identity())) { other.beforeTest(random(), 0); final ClusterState first = internalCluster().getInstance(ClusterService.class).state(); final ClusterState second = other.getInstance(ClusterService.class).state(); assertThat(first.nodes().getSize(), equalTo(1)); assertThat(second.nodes().getSize(), equalTo(1)); assertThat( first.nodes().getMasterNodeId(), not(equalTo(second.nodes().getMasterNodeId()))); assertThat( first.metaData().clusterUUID(), not(equalTo(second.metaData().clusterUUID()))); } } }