/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF 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.apache.flink.runtime.leaderelection; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.test.TestingServer; import org.apache.flink.configuration.Configuration; import org.apache.flink.configuration.HighAvailabilityOptions; import org.apache.flink.runtime.blob.VoidBlobStore; import org.apache.flink.runtime.highavailability.HighAvailabilityServices; import org.apache.flink.runtime.highavailability.HighAvailabilityServicesUtils; import org.apache.flink.runtime.highavailability.zookeeper.ZooKeeperHaServices; import org.apache.flink.runtime.jobmaster.JobMaster; import org.apache.flink.runtime.leaderretrieval.LeaderRetrievalService; import org.apache.flink.runtime.rpc.akka.AkkaRpcServiceUtils; import org.apache.flink.runtime.testingUtils.TestingUtils; import org.apache.flink.runtime.util.LeaderRetrievalUtils; import org.apache.flink.runtime.util.ZooKeeperUtils; import org.apache.flink.util.TestLogger; import org.junit.After; import org.junit.Before; import org.junit.Test; import scala.concurrent.duration.FiniteDuration; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import java.net.UnknownHostException; import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; public class ZooKeeperLeaderRetrievalTest extends TestLogger{ private TestingServer testingServer; private Configuration config; private HighAvailabilityServices highAvailabilityServices; @Before public void before() throws Exception { testingServer = new TestingServer(); config = new Configuration(); config.setString(HighAvailabilityOptions.HA_MODE, "zookeeper"); config.setString(HighAvailabilityOptions.HA_ZOOKEEPER_QUORUM, testingServer.getConnectString()); CuratorFramework client = ZooKeeperUtils.startCuratorFramework(config); highAvailabilityServices = new ZooKeeperHaServices( client, TestingUtils.defaultExecutor(), config, new VoidBlobStore()); } @After public void after() throws Exception { if(testingServer != null) { testingServer.stop(); testingServer = null; } if (highAvailabilityServices != null) { highAvailabilityServices.closeAndCleanupAllData(); highAvailabilityServices = null; } } /** * Tests that LeaderRetrievalUtils.findConnectingAddress finds the correct connecting address * in case of an old leader address in ZooKeeper and a subsequent election of a new leader. * The findConnectingAddress should block until the new leader has been elected and his * address has been written to ZooKeeper. */ @Test public void testConnectingAddressRetrievalWithDelayedLeaderElection() throws Exception { FiniteDuration timeout = new FiniteDuration(1, TimeUnit.MINUTES); long sleepingTime = 1000; LeaderElectionService leaderElectionService = null; LeaderElectionService faultyLeaderElectionService; ServerSocket serverSocket; InetAddress localHost; Thread thread; try { String wrongAddress = AkkaRpcServiceUtils.getRpcUrl( "1.1.1.1", 1234, "foobar", HighAvailabilityServicesUtils.AddressResolution.NO_ADDRESS_RESOLUTION, config); try { localHost = InetAddress.getLocalHost(); serverSocket = new ServerSocket(0, 50, localHost); } catch (UnknownHostException e) { // may happen if disconnected. skip test. System.err.println("Skipping 'testNetworkInterfaceSelection' test."); return; } catch (IOException e) { // may happen in certain test setups, skip test. System.err.println("Skipping 'testNetworkInterfaceSelection' test."); return; } InetSocketAddress correctInetSocketAddress = new InetSocketAddress(localHost, serverSocket.getLocalPort()); String correctAddress = AkkaRpcServiceUtils.getRpcUrl( localHost.getHostName(), correctInetSocketAddress.getPort(), JobMaster.JOB_MANAGER_NAME, HighAvailabilityServicesUtils.AddressResolution.NO_ADDRESS_RESOLUTION, config); faultyLeaderElectionService = highAvailabilityServices.getJobManagerLeaderElectionService( HighAvailabilityServices.DEFAULT_JOB_ID); TestingContender wrongLeaderAddressContender = new TestingContender(wrongAddress, faultyLeaderElectionService); faultyLeaderElectionService.start(wrongLeaderAddressContender); FindConnectingAddress findConnectingAddress = new FindConnectingAddress( timeout, highAvailabilityServices.getJobManagerLeaderRetriever(HighAvailabilityServices.DEFAULT_JOB_ID)); thread = new Thread(findConnectingAddress); thread.start(); leaderElectionService = highAvailabilityServices.getJobManagerLeaderElectionService(HighAvailabilityServices.DEFAULT_JOB_ID); TestingContender correctLeaderAddressContender = new TestingContender(correctAddress, leaderElectionService); Thread.sleep(sleepingTime); faultyLeaderElectionService.stop(); leaderElectionService.start(correctLeaderAddressContender); thread.join(); InetAddress result = findConnectingAddress.getInetAddress(); // check that we can connect to the localHost Socket socket = new Socket(); try { // port 0 = let the OS choose the port SocketAddress bindP = new InetSocketAddress(result, 0); // machine socket.bind(bindP); socket.connect(correctInetSocketAddress, 1000); } finally { socket.close(); } } finally { if (leaderElectionService != null) { leaderElectionService.stop(); } } } /** * Tests that the LeaderRetrievalUtils.findConnectingAddress stops trying to find the * connecting address if no leader address has been specified. The call should return * then InetAddress.getLocalHost(). */ @Test public void testTimeoutOfFindConnectingAddress() throws Exception { FiniteDuration timeout = new FiniteDuration(10L, TimeUnit.SECONDS); LeaderRetrievalService leaderRetrievalService = highAvailabilityServices.getJobManagerLeaderRetriever(HighAvailabilityServices.DEFAULT_JOB_ID); InetAddress result = LeaderRetrievalUtils.findConnectingAddress(leaderRetrievalService, timeout); assertEquals(InetAddress.getLocalHost(), result); } static class FindConnectingAddress implements Runnable { private final FiniteDuration timeout; private final LeaderRetrievalService leaderRetrievalService; private InetAddress result; private Exception exception; public FindConnectingAddress( FiniteDuration timeout, LeaderRetrievalService leaderRetrievalService) { this.timeout = timeout; this.leaderRetrievalService = leaderRetrievalService; } @Override public void run() { try { result = LeaderRetrievalUtils.findConnectingAddress( leaderRetrievalService, timeout); } catch (Exception e) { exception = e; } } public InetAddress getInetAddress() throws Exception { if (exception != null) { throw exception; } else { return result; } } } }