Repository: knox Updated Branches: refs/heads/master a1e1b207b -> 1b053c5e1
KNOX-1149 - HBase High Availability Fails with Kerberos Secured Cluster Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/1b053c5e Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/1b053c5e Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/1b053c5e Branch: refs/heads/master Commit: 1b053c5e11b6fca3e88c0ccfb4911e4c8bba5bed Parents: a1e1b20 Author: Phil Zampino <[email protected]> Authored: Wed May 23 09:58:39 2018 -0400 Committer: Phil Zampino <[email protected]> Committed: Thu May 24 13:01:44 2018 -0400 ---------------------------------------------------------------------- .../provider/impl/BaseZookeeperURLManager.java | 96 +++++++++++++++----- .../provider/impl/HBaseZookeeperURLManager.java | 52 +++++++---- .../impl/HBaseZookeeperURLManagerTest.java | 26 +++++- 3 files changed, 131 insertions(+), 43 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/1b053c5e/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/BaseZookeeperURLManager.java ---------------------------------------------------------------------- diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/BaseZookeeperURLManager.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/BaseZookeeperURLManager.java index 868fda8..8262f8d 100644 --- a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/BaseZookeeperURLManager.java +++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/BaseZookeeperURLManager.java @@ -17,17 +17,28 @@ */ package org.apache.knox.gateway.ha.provider.impl; +import java.security.Principal; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentLinkedQueue; import org.apache.commons.io.IOUtils; +import org.apache.knox.gateway.config.GatewayConfig; +import org.apache.knox.gateway.dispatch.KnoxSpnegoAuthSchemeFactory; import org.apache.knox.gateway.ha.provider.HaServiceConfig; import org.apache.knox.gateway.ha.provider.URLManager; import org.apache.knox.gateway.ha.provider.impl.i18n.HaMessages; import org.apache.knox.gateway.i18n.messages.MessagesFactory; +import org.apache.http.auth.AuthSchemeProvider; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.AuthSchemes; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpGet; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; @@ -46,7 +57,7 @@ public abstract class BaseZookeeperURLManager implements URLManager { /** * Host Ping Timeout */ - private static final int TIMEOUT = 2000; + private static final int TIMEOUT = 5000; private String zooKeeperEnsemble; private String zooKeeperNamespace; @@ -63,11 +74,7 @@ public abstract class BaseZookeeperURLManager implements URLManager { } String zookeeperEnsemble = config.getZookeeperEnsemble(); - if (zookeeperEnsemble != null && zookeeperEnsemble.trim().length() > 0) { - return true; - } - - return false; + return zookeeperEnsemble != null && (zookeeperEnsemble.trim().length() > 0); } @Override @@ -157,45 +164,84 @@ public abstract class BaseZookeeperURLManager implements URLManager { protected List<String> validateHosts(List<String> hosts, String suffix, String acceptHeader) { List<String> result = new ArrayList<String>(); - CloseableHttpClient client = null; + CloseableHttpClient client = buildHttpClient(); try { - // Construct a HttpClient with short term timeout - RequestConfig.Builder requestBuilder = RequestConfig.custom() - .setConnectTimeout(TIMEOUT) - .setSocketTimeout(TIMEOUT) - .setConnectionRequestTimeout(TIMEOUT); - - client = HttpClientBuilder.create() - .setDefaultRequestConfig(requestBuilder.build()) - .build(); - for(String host: hosts) { try { HttpGet get = new HttpGet(host + suffix); - + if (acceptHeader != null) { get.setHeader("Accept", acceptHeader); } - + + // Ping host String response = client.execute(get, new StringResponseHandler()); if (response != null) { result.add(host); } - } - catch (Exception ex) { + } catch (Exception ex) { // ignore host } } - } - catch (Exception ex) { + } catch (Exception e) { // Ignore errors - } - finally { + } finally { IOUtils.closeQuietly(client); } return result; } + + /** + * Construct an Apache HttpClient with suitable timeout and authentication. + * + * @return Apache HttpClient + */ + private CloseableHttpClient buildHttpClient() { + CloseableHttpClient client = null; + + // Construct a HttpClient with short term timeout + RequestConfig.Builder requestBuilder = RequestConfig.custom() + .setConnectTimeout(TIMEOUT) + .setSocketTimeout(TIMEOUT) + .setConnectionRequestTimeout(TIMEOUT); + + // If Kerberos is enabled, allow for challenge/response transparent to client + if (Boolean.getBoolean(GatewayConfig.HADOOP_KERBEROS_SECURED)) { + CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(AuthScope.ANY, new NullCredentials()); + + Registry<AuthSchemeProvider> authSchemeRegistry = + RegistryBuilder.<AuthSchemeProvider>create() + .register(AuthSchemes.SPNEGO, new KnoxSpnegoAuthSchemeFactory(true)) + .build(); + + client = HttpClientBuilder.create() + .setDefaultRequestConfig(requestBuilder.build()) + .setDefaultAuthSchemeRegistry(authSchemeRegistry) + .setDefaultCredentialsProvider(credentialsProvider) + .build(); + } else { + client = HttpClientBuilder.create() + .setDefaultRequestConfig(requestBuilder.build()) + .build(); + } + + return client; + } + + private static class NullCredentials implements Credentials { + @Override + public Principal getUserPrincipal() { + return null; + } + + @Override + public String getPassword() { + return null; + } + } + } http://git-wip-us.apache.org/repos/asf/knox/blob/1b053c5e/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HBaseZookeeperURLManager.java ---------------------------------------------------------------------- diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HBaseZookeeperURLManager.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HBaseZookeeperURLManager.java index d2053cd..e4ffc12 100644 --- a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HBaseZookeeperURLManager.java +++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/HBaseZookeeperURLManager.java @@ -44,7 +44,10 @@ public class HBaseZookeeperURLManager extends BaseZookeeperURLManager { */ private static final int PORT_NUMBER = 8080; - private static final String DEFAULT_ZOOKEEPER_NAMESPACE = "/hbase-unsecure"; + private static final String DEFAULT_ZOOKEEPER_NAMESPACE_SECURE = "/hbase-secure"; + + private static final String DEFAULT_ZOOKEEPER_NAMESPACE_UNSECURE = "/hbase-unsecure"; + // ------------------------------------------------------------------------------------- // Abstract methods @@ -59,9 +62,9 @@ public class HBaseZookeeperURLManager extends BaseZookeeperURLManager { protected List<String> lookupURLs() { // Retrieve list of potential hosts from ZooKeeper List<String> hosts = retrieveHosts(); - + // Validate access to hosts using cheap ping style operation - List<String> validatedHosts = validateHosts(hosts,"/","text/xml"); + List<String> validatedHosts = validateHosts(hosts,"/version/rest","text/xml"); // Randomize the hosts list for simple load balancing if (!validatedHosts.isEmpty()) { @@ -77,8 +80,7 @@ public class HBaseZookeeperURLManager extends BaseZookeeperURLManager { @Override protected String getZookeeperNamespace() { - String ns = super.getZookeeperNamespace(); - return (ns == null || ns.isEmpty()) ? DEFAULT_ZOOKEEPER_NAMESPACE : ns; + return super.getZookeeperNamespace(); } // ------------------------------------------------------------------------------------- @@ -100,17 +102,33 @@ public class HBaseZookeeperURLManager extends BaseZookeeperURLManager { try { zooKeeperClient.start(); + List<String> serverNodes = null; + String namespace = getZookeeperNamespace(); - if (!namespace.startsWith("/")) { - namespace = "/" + namespace; + if (namespace != null && !namespace.isEmpty()) { + if (!namespace.startsWith("/")) { + namespace = "/" + namespace; + } + serverNodes = zooKeeperClient.getChildren().forPath(namespace + "/rs"); + } else { + // If no namespace is explicitly specified, try the default secure namespace + try { + serverNodes = zooKeeperClient.getChildren().forPath(DEFAULT_ZOOKEEPER_NAMESPACE_SECURE + "/rs"); + } catch (Exception e) { + // Ignore -- znode may not exist + } + + if (serverNodes == null || serverNodes.isEmpty()) { + // Fall back to the default unsecure namespace if no secure nodes are found + serverNodes = zooKeeperClient.getChildren().forPath(DEFAULT_ZOOKEEPER_NAMESPACE_UNSECURE + "/rs"); + } } - // Retrieve list of all region server hosts - List<String> serverNodes = zooKeeperClient.getChildren().forPath(namespace + "/rs"); - - for (String serverNode : serverNodes) { - String serverURL = constructURL(serverNode); - serverHosts.add(serverURL); + if (serverNodes != null) { + for (String serverNode : serverNodes) { + String serverURL = constructURL(serverNode); + serverHosts.add(serverURL); + } } } catch (Exception e) { LOG.failedToGetZookeeperUrls(e); @@ -121,10 +139,10 @@ public class HBaseZookeeperURLManager extends BaseZookeeperURLManager { zooKeeperClient.close(); } } - + return serverHosts; } - + /** * Given a String of the format "host,number,number" convert to a URL of the format * "http://host:port". @@ -140,10 +158,10 @@ public class HBaseZookeeperURLManager extends BaseZookeeperURLManager { buffer.append(scheme); buffer.append("://"); // Strip off the host name - buffer.append(serverInfo.substring(0,serverInfo.indexOf(","))); + buffer.append(serverInfo.substring(0, serverInfo.indexOf(","))); buffer.append(":"); buffer.append(PORT_NUMBER); - + return buffer.toString(); } } http://git-wip-us.apache.org/repos/asf/knox/blob/1b053c5e/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/provider/impl/HBaseZookeeperURLManagerTest.java ---------------------------------------------------------------------- diff --git a/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/provider/impl/HBaseZookeeperURLManagerTest.java b/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/provider/impl/HBaseZookeeperURLManagerTest.java index 1869890..a4166f4 100644 --- a/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/provider/impl/HBaseZookeeperURLManagerTest.java +++ b/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/provider/impl/HBaseZookeeperURLManagerTest.java @@ -18,6 +18,9 @@ package org.apache.knox.gateway.ha.provider.impl; import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; @@ -68,13 +71,33 @@ public class HBaseZookeeperURLManagerTest { doTest(SECURE_NS); } + /** + * KNOX-1149 + */ + @Test + public void testDefaultNSHBaseZookeeperURLManagerLoadingWhenSecureAndUnsecureZNodesPresent() throws Exception { + createZNodes(UNSECURE_NS); + createZNodes(SECURE_NS); + doTest(null); + } + + /** + * KNOX-1149 + */ + @Test + public void testSpecifiedNSHBaseZookeeperURLManagerLoadingWhenSecureAndUnsecureZNodesPresent() throws Exception { + createZNodes(UNSECURE_NS); + createZNodes(SECURE_NS); + doTest(UNSECURE_NS); + } + @Test public void testSecureNSHBaseZookeeperURLManagerLoadingNoLeadingSlash() throws Exception { createZNodes(SECURE_NS); doTest(SECURE_NS.substring(1)); // Omit the leading slash from the namespace } - private void doTest(String namespace) throws Exception { + private void doTest(String namespace) { HaServiceConfig config = new DefaultHaServiceConfig("WEBHBASE"); config.setEnabled(true); config.setZookeeperEnsemble(cluster.getConnectString()); @@ -89,6 +112,7 @@ public class HBaseZookeeperURLManagerTest { Assert.assertTrue(manager instanceof HBaseZookeeperURLManager); } + private void createZNodes(String namespace) throws Exception { CuratorFramework zooKeeperClient = CuratorFrameworkFactory.builder().connectString(cluster.getConnectString())
