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())

Reply via email to