You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by pz...@apache.org on 2018/03/23 18:58:44 UTC

knox git commit: KNOX-1224 - Knox Proxy HADispatcher to support Atlas in HA (Nixon Rodrigues via Phil Zampino)

Repository: knox
Updated Branches:
  refs/heads/master 591e0bd3c -> a6d2f5240


KNOX-1224 - Knox Proxy HADispatcher to support Atlas in HA (Nixon Rodrigues via Phil Zampino)


Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/a6d2f524
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/a6d2f524
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/a6d2f524

Branch: refs/heads/master
Commit: a6d2f52409e1b9cf497d76cd799ad73f17579092
Parents: 591e0bd
Author: Phil Zampino <pz...@apache.org>
Authored: Fri Mar 23 14:10:21 2018 -0400
Committer: Phil Zampino <pz...@apache.org>
Committed: Fri Mar 23 14:10:41 2018 -0400

----------------------------------------------------------------------
 .../gateway/ha/dispatch/AtlasApiHaDispatch.java |  82 ++++++++++++
 .../gateway/ha/dispatch/AtlasHaDispatch.java    |  81 ++++++++++++
 .../provider/impl/AtlasZookeeperURLManager.java |  95 ++++++++++++++
 ...g.apache.knox.gateway.ha.provider.URLManager |   3 +-
 .../impl/AtlasZookeeperURLManagerTest.java      | 129 +++++++++++++++++++
 .../services/atlas-api/0.8.0/service.xml        |   2 +-
 .../resources/services/atlas/0.8.0/service.xml  |   4 +-
 7 files changed, 392 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/knox/blob/a6d2f524/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/AtlasApiHaDispatch.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/AtlasApiHaDispatch.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/AtlasApiHaDispatch.java
new file mode 100644
index 0000000..59fbb9e
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/AtlasApiHaDispatch.java
@@ -0,0 +1,82 @@
+/*
+ * 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.knox.gateway.ha.dispatch;
+
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpUriRequest;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class AtlasApiHaDispatch extends DefaultHaDispatch {
+
+    private static Set<String> REQUEST_EXCLUDE_HEADERS = new HashSet<>();
+
+    static {
+        REQUEST_EXCLUDE_HEADERS.add("Content-Length");
+    }
+
+    public AtlasApiHaDispatch() {
+        setServiceRole("ATLAS-API");
+    }
+
+    @Override
+    public void init() {
+        super.init();
+    }
+
+    @Override
+    public Set<String> getOutboundResponseExcludeHeaders() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set<String> getOutboundRequestExcludeHeaders() {
+        return REQUEST_EXCLUDE_HEADERS;
+    }
+
+
+    @Override
+    protected void executeRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse) throws IOException {
+        HttpResponse inboundResponse = null;
+        try {
+            inboundResponse = executeOutboundRequest(outboundRequest);
+            int statusCode = inboundResponse.getStatusLine().getStatusCode();
+            Header originalLocationHeader = inboundResponse.getFirstHeader("Location");
+
+
+            if ((statusCode == HttpServletResponse.SC_MOVED_TEMPORARILY || statusCode == HttpServletResponse.SC_TEMPORARY_REDIRECT) && originalLocationHeader != null) {
+                inboundResponse.removeHeaders("Location");
+                failoverRequest(outboundRequest, inboundRequest, outboundResponse, inboundResponse, new Exception("Atlas HA redirection"));
+            }
+
+            writeOutboundResponse(outboundRequest, inboundRequest, outboundResponse, inboundResponse);
+
+        } catch (IOException e) {
+            LOG.errorConnectingToServer(outboundRequest.getURI().toString(), e);
+            failoverRequest(outboundRequest, inboundRequest, outboundResponse, inboundResponse, e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/a6d2f524/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/AtlasHaDispatch.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/AtlasHaDispatch.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/AtlasHaDispatch.java
new file mode 100644
index 0000000..8d2490d
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/dispatch/AtlasHaDispatch.java
@@ -0,0 +1,81 @@
+/*
+ * 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.knox.gateway.ha.dispatch;
+
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpUriRequest;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class AtlasHaDispatch extends DefaultHaDispatch {
+    private static Set<String> REQUEST_EXCLUDE_HEADERS = new HashSet<>();
+
+    static {
+        REQUEST_EXCLUDE_HEADERS.add("Content-Length");
+    }
+
+    public AtlasHaDispatch() {
+        setServiceRole("ATLAS");
+    }
+
+    @Override
+    public void init() {
+        super.init();
+    }
+
+    @Override
+    public Set<String> getOutboundResponseExcludeHeaders() {
+        return Collections.emptySet();
+    }
+
+    @Override
+    public Set<String> getOutboundRequestExcludeHeaders() {
+        return REQUEST_EXCLUDE_HEADERS;
+    }
+
+    @Override
+    protected void executeRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse) throws IOException {
+        HttpResponse inboundResponse = null;
+        try {
+            inboundResponse = executeOutboundRequest(outboundRequest);
+
+            int statusCode = inboundResponse.getStatusLine().getStatusCode();
+            Header originalLocationHeader = inboundResponse.getFirstHeader("Location");
+
+            if((statusCode == HttpServletResponse.SC_MOVED_TEMPORARILY || statusCode == HttpServletResponse.SC_TEMPORARY_REDIRECT)
+                    && originalLocationHeader != null &&  !originalLocationHeader.getValue().endsWith("login.jsp")){
+                inboundResponse.removeHeaders("Location");
+                failoverRequest(outboundRequest, inboundRequest, outboundResponse, inboundResponse, new Exception("Atlas HA redirection"));
+            }
+
+            writeOutboundResponse(outboundRequest, inboundRequest, outboundResponse, inboundResponse);
+
+        } catch (IOException e) {
+            LOG.errorConnectingToServer(outboundRequest.getURI().toString(), e);
+            failoverRequest(outboundRequest, inboundRequest, outboundResponse, inboundResponse, e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/a6d2f524/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/AtlasZookeeperURLManager.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/AtlasZookeeperURLManager.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/AtlasZookeeperURLManager.java
new file mode 100644
index 0000000..0f28c37
--- /dev/null
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/provider/impl/AtlasZookeeperURLManager.java
@@ -0,0 +1,95 @@
+/*
+ * 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.knox.gateway.ha.provider.impl;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.knox.gateway.ha.provider.HaServiceConfig;
+import org.apache.knox.gateway.ha.provider.impl.i18n.HaMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+
+import java.nio.charset.Charset;
+import java.util.*;
+
+public class AtlasZookeeperURLManager extends DefaultURLManager {
+    private static final HaMessages LOG = MessagesFactory.get(HaMessages.class);
+
+    private String zooKeeperEnsemble;
+
+    private String zooKeeperNamespace;
+
+    public static final String APACHE_ATLAS_ACTIVE_SERVER_INFO = "/active_server_info";
+
+
+    @Override
+    public boolean supportsConfig(HaServiceConfig config) {
+        if (!( config.getServiceName().equalsIgnoreCase("ATLAS") || config.getServiceName().equalsIgnoreCase("ATLAS-API"))) {
+            return false;
+        }
+        String zookeeperEnsemble = config.getZookeeperEnsemble();
+        String zookeeperNamespace = config.getZookeeperNamespace();
+        return zookeeperEnsemble != null && zookeeperNamespace != null && !zookeeperEnsemble.trim().isEmpty() && !zookeeperNamespace.trim().isEmpty();
+    }
+
+    @Override
+    public void setConfig(HaServiceConfig config) {
+        zooKeeperEnsemble = config.getZookeeperEnsemble();
+        zooKeeperNamespace = config.getZookeeperNamespace();
+        setURLs(lookupURLs());
+    }
+
+    public List<String> lookupURLs() {
+
+        List<String> serverHosts = new ArrayList<>();
+        CuratorFramework zooKeeperClient =
+                CuratorFrameworkFactory.builder().connectString(zooKeeperEnsemble)
+                                                 .retryPolicy(new ExponentialBackoffRetry(1000, 3))
+                                                 .build();
+        try {
+
+            zooKeeperClient.start();
+
+            byte[] bytes = zooKeeperClient.getData().forPath("/" + zooKeeperNamespace + APACHE_ATLAS_ACTIVE_SERVER_INFO);
+
+            String activeURL = new String(bytes, Charset.forName("UTF-8"));
+
+            serverHosts.add(activeURL);
+
+        } catch (Exception e) {
+
+            LOG.failedToGetZookeeperUrls(e);
+            throw new RuntimeException(e);
+        } finally {
+            // Close the client connection with ZooKeeper
+            if (zooKeeperClient != null) {
+                zooKeeperClient.close();
+            }
+        }
+        return serverHosts;
+    }
+
+
+
+    @Override
+    public synchronized void markFailed(String url) {
+        setURLs(lookupURLs());
+        super.markFailed(url);
+    }
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/a6d2f524/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.knox.gateway.ha.provider.URLManager
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.knox.gateway.ha.provider.URLManager b/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.knox.gateway.ha.provider.URLManager
index d6b9608..2c74b77 100644
--- a/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.knox.gateway.ha.provider.URLManager
+++ b/gateway-provider-ha/src/main/resources/META-INF/services/org.apache.knox.gateway.ha.provider.URLManager
@@ -19,4 +19,5 @@
 org.apache.knox.gateway.ha.provider.impl.HS2ZookeeperURLManager
 org.apache.knox.gateway.ha.provider.impl.SOLRZookeeperURLManager
 org.apache.knox.gateway.ha.provider.impl.KafkaZookeeperURLManager
-org.apache.knox.gateway.ha.provider.impl.HBaseZookeeperURLManager
\ No newline at end of file
+org.apache.knox.gateway.ha.provider.impl.HBaseZookeeperURLManager
+org.apache.knox.gateway.ha.provider.impl.AtlasZookeeperURLManager

http://git-wip-us.apache.org/repos/asf/knox/blob/a6d2f524/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/provider/impl/AtlasZookeeperURLManagerTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/provider/impl/AtlasZookeeperURLManagerTest.java b/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/provider/impl/AtlasZookeeperURLManagerTest.java
new file mode 100644
index 0000000..56f4061
--- /dev/null
+++ b/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/provider/impl/AtlasZookeeperURLManagerTest.java
@@ -0,0 +1,129 @@
+/**
+ * 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.knox.gateway.ha.provider.impl;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.apache.curator.test.TestingCluster;
+import org.apache.knox.gateway.ha.provider.HaServiceConfig;
+import org.apache.knox.gateway.ha.provider.URLManager;
+import org.apache.knox.gateway.ha.provider.URLManagerLoader;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+public class AtlasZookeeperURLManagerTest {
+
+    private TestingCluster cluster;
+    private AtlasZookeeperURLManager manager;
+    private static String atlasNode1 = "http://atlas.node1:21000";
+    private static String atlasNode2 = "http://atlas.node2:21000";
+
+    @Before
+    public void setup() throws Exception {
+        cluster = new TestingCluster(3);
+        cluster.start();
+
+        CuratorFramework zooKeeperClient =
+                CuratorFrameworkFactory.builder().connectString(cluster.getConnectString())
+                                                 .retryPolicy(new ExponentialBackoffRetry(1000, 3))
+                                                 .build();
+
+        zooKeeperClient.start();
+        zooKeeperClient.create().forPath("/apache_atlas");
+        zooKeeperClient.create().forPath("/apache_atlas/active_server_info");
+        zooKeeperClient.setData().forPath("/apache_atlas/active_server_info",
+                                          atlasNode1.getBytes(Charset.forName("UTF-8")));
+        zooKeeperClient.close();
+        setAtlasActiveHostURLInZookeeper(atlasNode1);
+
+        manager = new AtlasZookeeperURLManager();
+        HaServiceConfig config = new DefaultHaServiceConfig("ATLAS-API");
+        config.setEnabled(true);
+        config.setZookeeperEnsemble(cluster.getConnectString());
+        config.setZookeeperNamespace("apache_atlas");
+        manager.setConfig(config);
+    }
+
+    @After
+    public void teardown() throws IOException {
+        cluster.stop();
+    }
+
+    @Test
+    public void testAtlasActiveUrlIsSetCorrectlyAfterLookUpFromZK() {
+        manager.lookupURLs();
+        List<String> urls = manager.getURLs();
+        assertEquals(atlasNode1, urls.get(0));
+    }
+
+    @Test
+    public void testMarkFailedCorrectlyResetTheEarlierUrl() throws Exception {
+        setAtlasActiveHostURLInZookeeper(atlasNode2);
+
+        manager.markFailed("http://atlas.node1:21000");
+        List<String> urls = manager.getURLs();
+        assertNotEquals(atlasNode1, urls.get(0));
+        assertEquals(atlasNode2, urls.get(0));
+    }
+
+    @Test
+    public void testAtlasURLManagerLoadingForAtlasApiService() {
+        HaServiceConfig config = new DefaultHaServiceConfig("ATLAS-API");
+        config.setEnabled(true);
+        config.setZookeeperEnsemble(cluster.getConnectString());
+        config.setZookeeperNamespace("apache_atlas");
+        URLManager manager = URLManagerLoader.loadURLManager(config);
+        Assert.assertNotNull(manager);
+        Assert.assertTrue(manager instanceof AtlasZookeeperURLManager);
+    }
+
+    @Test
+    public void testAtlasURLManagerLoadingForAtlasUIService() {
+        HaServiceConfig config = new DefaultHaServiceConfig("ATLAS");
+        config.setEnabled(true);
+        config.setZookeeperEnsemble(cluster.getConnectString());
+        config.setZookeeperNamespace("apache_atlas");
+        URLManager manager = URLManagerLoader.loadURLManager(config);
+        Assert.assertNotNull(manager);
+        Assert.assertTrue(manager instanceof AtlasZookeeperURLManager);
+    }
+
+    void setAtlasActiveHostURLInZookeeper(String activeURL) throws Exception {
+
+        CuratorFramework zooKeeperClient =
+                CuratorFrameworkFactory.builder().connectString(cluster.getConnectString())
+                                                 .retryPolicy(new ExponentialBackoffRetry(1000, 3))
+                                                 .build();
+
+        zooKeeperClient.start();
+        zooKeeperClient.setData().forPath("/apache_atlas/active_server_info",
+                                          activeURL.getBytes(Charset.forName("UTF-8")));
+        zooKeeperClient.close();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/knox/blob/a6d2f524/gateway-service-definitions/src/main/resources/services/atlas-api/0.8.0/service.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/main/resources/services/atlas-api/0.8.0/service.xml b/gateway-service-definitions/src/main/resources/services/atlas-api/0.8.0/service.xml
index 3ae7b24..20662ac 100644
--- a/gateway-service-definitions/src/main/resources/services/atlas-api/0.8.0/service.xml
+++ b/gateway-service-definitions/src/main/resources/services/atlas-api/0.8.0/service.xml
@@ -28,5 +28,5 @@
         <route path="/atlas/api/**"/>
     </routes>
 
-    <dispatch classname="org.apache.knox.gateway.dispatch.PassAllHeadersDispatch"/>
+    <dispatch classname="org.apache.knox.gateway.dispatch.PassAllHeadersDispatch" ha-classname="org.apache.knox.gateway.ha.dispatch.AtlasApiHaDispatch"/>
 </service>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/knox/blob/a6d2f524/gateway-service-definitions/src/main/resources/services/atlas/0.8.0/service.xml
----------------------------------------------------------------------
diff --git a/gateway-service-definitions/src/main/resources/services/atlas/0.8.0/service.xml b/gateway-service-definitions/src/main/resources/services/atlas/0.8.0/service.xml
index 6d99f30..8899248 100644
--- a/gateway-service-definitions/src/main/resources/services/atlas/0.8.0/service.xml
+++ b/gateway-service-definitions/src/main/resources/services/atlas/0.8.0/service.xml
@@ -46,6 +46,6 @@
 
     </routes>
 
-    <dispatch classname="org.apache.knox.gateway.dispatch.PassAllHeadersDispatch"/>
+    <dispatch classname="org.apache.knox.gateway.dispatch.PassAllHeadersDispatch" ha-classname="org.apache.knox.gateway.ha.dispatch.AtlasHaDispatch" />
 
-</service>
\ No newline at end of file
+</service>