/** * 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.hive.jdbc; import com.google.common.base.Joiner; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.recipes.nodes.PersistentEphemeralNode; import org.apache.curator.retry.RetryOneTime; import org.apache.curator.test.TestingServer; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.ql.util.ZooKeeperHiveHelper; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.junit.After; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; /** * Test Hive dynamic service discovery. */ public class TestServiceDiscovery { private static TestingServer server; private static CuratorFramework client; private static String rootNamespace = "hiveserver2"; @BeforeClass public static void setup() throws Exception { server = new TestingServer(); CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder(); client = builder.connectString(server.getConnectString()).retryPolicy(new RetryOneTime(1)).build(); client.start(); } @After public void teardown() throws Exception { client.close(); server.close(); server = null; } @Test public void testConnect() throws Exception { Map<String, String> confs = new HashMap<String, String>(); confs.put("hive.server2.thrift.bind.host", "host-1"); confs.put("hive.server2.transport.mode", "binary"); confs.put("hive.server2.thrift.port", "8000"); confs.put("hive.server2.authentication", "PLAIN"); publishConfsToZk(confs, "uri1"); confs.clear(); confs.put("hive.server2.thrift.bind.host", "host-2"); confs.put("hive.server2.transport.mode", "binary"); confs.put("hive.server2.thrift.port", "9000"); confs.put("hive.server2.authentication", "PLAIN"); publishConfsToZk(confs, "uri2"); confs.clear(); confs.put("hive.server2.thrift.bind.host", "host-3"); confs.put("hive.server2.transport.mode", "binary"); confs.put("hive.server2.thrift.port", "10000"); confs.put("hive.server2.authentication", "PLAIN"); publishConfsToZk(confs, "uri3"); Utils.JdbcConnectionParams connParams = new Utils.JdbcConnectionParams(); connParams.setZooKeeperEnsemble(server.getConnectString()); connParams.getSessionVars().put(Utils.JdbcConnectionParams.ZOOKEEPER_NAMESPACE, "hiveserver2"); List<ConnParamInfo> allConnectParams = new ArrayList<>(); while (true) { //Reject all paths to force it to continue. When no more paths, should throw an exception. try { ZooKeeperHiveClientHelper.configureConnParams(connParams); } catch (ZooKeeperHiveClientException e) { break; } connParams.getRejectedHostZnodePaths().add(connParams.getCurrentHostZnodePath()); allConnectParams.add(new ConnParamInfo(connParams.getHost(), connParams.getPort(), connParams.getCurrentHostZnodePath())); } //Make sure it itereated through all possible ConnParams Collection<ConnParamInfo> cp1 = Collections2.filter(allConnectParams, new ConnParamInfoPred("host-1", 8000, "serverUri=uri1")); Collection<ConnParamInfo> cp2 = Collections2.filter(allConnectParams, new ConnParamInfoPred("host-2", 9000, "serverUri=uri2")); Collection<ConnParamInfo> cp3 = Collections2.filter(allConnectParams, new ConnParamInfoPred("host-3", 10000, "serverUri=uri3")); Assert.assertEquals(cp1.size(), 1); Assert.assertEquals(cp2.size(), 1); Assert.assertEquals(cp3.size(), 1); } //Helper classes for ConnParam comparison logics. private class ConnParamInfo { String host; int port; String path; public ConnParamInfo(String host, int port, String path) { this.host = host; this.port = port; this.path = path; } } private class ConnParamInfoPred implements Predicate<ConnParamInfo> { String host; int port; String pathPrefix; ConnParamInfoPred(String host, int port, String pathPrefix) { this.host = host; this.port = port; this.pathPrefix = pathPrefix; } @Override public boolean apply(ConnParamInfo inputParam) { return inputParam.host.equals(host) && inputParam.port == port && inputParam.path.startsWith(pathPrefix); } } //Mocks HS2 publishing logic. private void publishConfsToZk(Map<String, String> confs, String uri) throws Exception { try { client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT) .forPath(ZooKeeperHiveHelper.ZOOKEEPER_PATH_SEPARATOR + rootNamespace); } catch (KeeperException e) { Assert.assertTrue(e.code() == KeeperException.Code.NODEEXISTS); } String pathPrefix = ZooKeeperHiveHelper.ZOOKEEPER_PATH_SEPARATOR + rootNamespace + ZooKeeperHiveHelper.ZOOKEEPER_PATH_SEPARATOR + "serverUri=" + uri + ";" + "sequence="; String znodeData = ""; // Publish configs for this instance as the data on the node znodeData = Joiner.on(';').withKeyValueSeparator("=").join(confs); byte[] znodeDataUTF8 = znodeData.getBytes(Charset.forName("UTF-8")); PersistentEphemeralNode znode = new PersistentEphemeralNode(client, PersistentEphemeralNode.Mode.EPHEMERAL_SEQUENTIAL, pathPrefix, znodeDataUTF8); znode.start(); // We'll wait for 120s for node creation long znodeCreationTimeout = 120; if (!znode.waitForInitialCreate(znodeCreationTimeout, TimeUnit.SECONDS)) { throw new Exception("Max znode creation wait time: " + znodeCreationTimeout + "s exhausted"); } } }