You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2017/09/25 20:21:05 UTC
[07/22] knox git commit: KNOX-1014 - Service Discovery and Topology
Generation Framework (Phil Zampino via lmccay)
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandler.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandler.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandler.java
new file mode 100644
index 0000000..fb563fa
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandler.java
@@ -0,0 +1,186 @@
+/**
+ * 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.hadoop.gateway.topology.simple;
+
+import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
+import org.apache.hadoop.gateway.services.Service;
+import org.apache.hadoop.gateway.topology.discovery.DefaultServiceDiscoveryConfig;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscovery;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryFactory;
+
+import java.io.*;
+import java.util.*;
+
+
+/**
+ * Processes simple topology descriptors, producing full topology files, which can subsequently be deployed to the
+ * gateway.
+ */
+public class SimpleDescriptorHandler {
+
+ private static final Service[] NO_GATEWAY_SERVICES = new Service[]{};
+
+ private static final SimpleDescriptorMessages log = MessagesFactory.get(SimpleDescriptorMessages.class);
+
+ public static Map<String, File> handle(File desc) throws IOException {
+ return handle(desc, NO_GATEWAY_SERVICES);
+ }
+
+ public static Map<String, File> handle(File desc, Service...gatewayServices) throws IOException {
+ return handle(desc, desc.getParentFile(), gatewayServices);
+ }
+
+ public static Map<String, File> handle(File desc, File destDirectory) throws IOException {
+ return handle(desc, destDirectory, NO_GATEWAY_SERVICES);
+ }
+
+ public static Map<String, File> handle(File desc, File destDirectory, Service...gatewayServices) throws IOException {
+ return handle(SimpleDescriptorFactory.parse(desc.getAbsolutePath()), desc.getParentFile(), destDirectory, gatewayServices);
+ }
+
+ public static Map<String, File> handle(SimpleDescriptor desc, File srcDirectory, File destDirectory) {
+ return handle(desc, srcDirectory, destDirectory, NO_GATEWAY_SERVICES);
+ }
+
+ public static Map<String, File> handle(SimpleDescriptor desc, File srcDirectory, File destDirectory, Service...gatewayServices) {
+ Map<String, File> result = new HashMap<>();
+
+ File topologyDescriptor;
+
+ DefaultServiceDiscoveryConfig sdc = new DefaultServiceDiscoveryConfig(desc.getDiscoveryAddress());
+ sdc.setUser(desc.getDiscoveryUser());
+ sdc.setPasswordAlias(desc.getDiscoveryPasswordAlias());
+ ServiceDiscovery sd = ServiceDiscoveryFactory.get(desc.getDiscoveryType(), gatewayServices);
+ ServiceDiscovery.Cluster cluster = sd.discover(sdc, desc.getClusterName());
+
+ Map<String, List<String>> serviceURLs = new HashMap<>();
+
+ if (cluster != null) {
+ for (SimpleDescriptor.Service descService : desc.getServices()) {
+ String serviceName = descService.getName();
+
+ List<String> descServiceURLs = descService.getURLs();
+ if (descServiceURLs == null || descServiceURLs.isEmpty()) {
+ descServiceURLs = cluster.getServiceURLs(serviceName);
+ }
+
+ // If there is at least one URL associated with the service, then add it to the map
+ if (descServiceURLs != null && !descServiceURLs.isEmpty()) {
+ serviceURLs.put(serviceName, descServiceURLs);
+ } else {
+ log.failedToDiscoverClusterServiceURLs(serviceName, cluster.getName());
+ throw new IllegalStateException("ServiceDiscovery failed to resolve any URLs for " + serviceName +
+ ". Topology update aborted!");
+ }
+ }
+ } else {
+ log.failedToDiscoverClusterServices(desc.getClusterName());
+ }
+
+ topologyDescriptor = null;
+ File providerConfig = null;
+ try {
+ // Verify that the referenced provider configuration exists before attempting to reading it
+ providerConfig = resolveProviderConfigurationReference(desc.getProviderConfig(), srcDirectory);
+ if (providerConfig == null) {
+ log.failedToResolveProviderConfigRef(desc.getProviderConfig());
+ throw new IllegalArgumentException("Unresolved provider configuration reference: " +
+ desc.getProviderConfig() + " ; Topology update aborted!");
+ }
+ result.put("reference", providerConfig);
+
+ // TODO: Should the contents of the provider config be validated before incorporating it into the topology?
+
+ String topologyFilename = desc.getName();
+ if (topologyFilename == null) {
+ topologyFilename = desc.getClusterName();
+ }
+ topologyDescriptor = new File(destDirectory, topologyFilename + ".xml");
+ FileWriter fw = new FileWriter(topologyDescriptor);
+
+ fw.write("<topology>\n");
+
+ // Copy the externalized provider configuration content into the topology descriptor in-line
+ InputStreamReader policyReader = new InputStreamReader(new FileInputStream(providerConfig));
+ char[] buffer = new char[1024];
+ int count;
+ while ((count = policyReader.read(buffer)) > 0) {
+ fw.write(buffer, 0, count);
+ }
+ policyReader.close();
+
+ // Write the service declarations
+ for (String serviceName : serviceURLs.keySet()) {
+ fw.write(" <service>\n");
+ fw.write(" <role>" + serviceName + "</role>\n");
+ for (String url : serviceURLs.get(serviceName)) {
+ fw.write(" <url>" + url + "</url>\n");
+ }
+ fw.write(" </service>\n");
+ }
+
+ fw.write("</topology>\n");
+
+ fw.flush();
+ fw.close();
+ } catch (IOException e) {
+ log.failedToGenerateTopologyFromSimpleDescriptor(topologyDescriptor.getName(), e);
+ topologyDescriptor.delete();
+ }
+
+ result.put("topology", topologyDescriptor);
+ return result;
+ }
+
+
+ private static File resolveProviderConfigurationReference(String reference, File srcDirectory) {
+ File providerConfig;
+
+ // If the reference includes a path
+ if (reference.contains(File.separator)) {
+ // Check if it's an absolute path
+ providerConfig = new File(reference);
+ if (!providerConfig.exists()) {
+ // If it's not an absolute path, try treating it as a relative path
+ providerConfig = new File(srcDirectory, reference);
+ if (!providerConfig.exists()) {
+ providerConfig = null;
+ }
+ }
+ } else { // No file path, just a name
+ // Check if it's co-located with the referencing descriptor
+ providerConfig = new File(srcDirectory, reference);
+ if (!providerConfig.exists()) {
+ // Check the shared-providers config location
+ File sharedProvidersDir = new File(srcDirectory, "../shared-providers");
+ if (sharedProvidersDir.exists()) {
+ providerConfig = new File(sharedProvidersDir, reference);
+ if (!providerConfig.exists()) {
+ // Check if it's a valid name without the extension
+ providerConfig = new File(sharedProvidersDir, reference + ".xml");
+ if (!providerConfig.exists()) {
+ providerConfig = null;
+ }
+ }
+ }
+ }
+ }
+
+ return providerConfig;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorImpl.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorImpl.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorImpl.java
new file mode 100644
index 0000000..32ceba9
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorImpl.java
@@ -0,0 +1,111 @@
+/**
+ * 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.hadoop.gateway.topology.simple;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class SimpleDescriptorImpl implements SimpleDescriptor {
+
+ @JsonProperty("discovery-type")
+ private String discoveryType;
+
+ @JsonProperty("discovery-address")
+ private String discoveryAddress;
+
+ @JsonProperty("discovery-user")
+ private String discoveryUser;
+
+ @JsonProperty("discovery-pwd-alias")
+ private String discoveryPasswordAlias;
+
+ @JsonProperty("provider-config-ref")
+ private String providerConfig;
+
+ @JsonProperty("cluster")
+ private String cluster;
+
+ @JsonProperty("services")
+ private List<ServiceImpl> services;
+
+ private String name = null;
+
+ void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String getDiscoveryType() {
+ return discoveryType;
+ }
+
+ @Override
+ public String getDiscoveryAddress() {
+ return discoveryAddress;
+ }
+
+ @Override
+ public String getDiscoveryUser() {
+ return discoveryUser;
+ }
+
+ @Override
+ public String getDiscoveryPasswordAlias() {
+ return discoveryPasswordAlias;
+ }
+
+ @Override
+ public String getClusterName() {
+ return cluster;
+ }
+
+ @Override
+ public String getProviderConfig() {
+ return providerConfig;
+ }
+
+ @Override
+ public List<Service> getServices() {
+ List<Service> result = new ArrayList<>();
+ result.addAll(services);
+ return result;
+ }
+
+ public static class ServiceImpl implements Service {
+ private String name;
+ private List<String> urls;
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public List<String> getURLs() {
+ return urls;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorMessages.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorMessages.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorMessages.java
new file mode 100644
index 0000000..cf9aa28
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorMessages.java
@@ -0,0 +1,44 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.gateway.topology.simple;
+
+import org.apache.hadoop.gateway.i18n.messages.Message;
+import org.apache.hadoop.gateway.i18n.messages.MessageLevel;
+import org.apache.hadoop.gateway.i18n.messages.Messages;
+import org.apache.hadoop.gateway.i18n.messages.StackTrace;
+
+@Messages(logger="org.apache.gateway.topology.simple")
+public interface SimpleDescriptorMessages {
+
+ @Message(level = MessageLevel.ERROR,
+ text = "Service discovery for cluster {0} failed.")
+ void failedToDiscoverClusterServices(final String cluster);
+
+ @Message(level = MessageLevel.ERROR,
+ text = "No URLs were discovered for {0} in the {1} cluster.")
+ void failedToDiscoverClusterServiceURLs(final String serviceName, final String clusterName);
+
+ @Message(level = MessageLevel.ERROR,
+ text = "Failed to resolve the referenced provider configuration {0}.")
+ void failedToResolveProviderConfigRef(final String providerConfigRef);
+
+ @Message(level = MessageLevel.ERROR,
+ text = "Error generating topology {0} from simple descriptor: {1}")
+ void failedToGenerateTopologyFromSimpleDescriptor(final String topologyFile,
+ @StackTrace( level = MessageLevel.DEBUG ) Exception e );
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/test/java/org/apache/hadoop/gateway/services/topology/DefaultTopologyServiceTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/services/topology/DefaultTopologyServiceTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/services/topology/DefaultTopologyServiceTest.java
index 55cd5cc..498d750 100644
--- a/gateway-server/src/test/java/org/apache/hadoop/gateway/services/topology/DefaultTopologyServiceTest.java
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/services/topology/DefaultTopologyServiceTest.java
@@ -22,8 +22,12 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import org.apache.hadoop.gateway.config.GatewayConfig;
+import org.apache.hadoop.gateway.services.security.AliasService;
import org.apache.hadoop.gateway.services.topology.impl.DefaultTopologyService;
import org.apache.hadoop.gateway.topology.*;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscovery;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryConfig;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryFactory;
import org.apache.hadoop.test.TestUtils;
import org.easymock.EasyMock;
import org.junit.After;
@@ -36,6 +40,8 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.isA;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.core.IsNull.notNullValue;
@@ -78,9 +84,17 @@ public class DefaultTopologyServiceTest {
public void testGetTopologies() throws Exception {
File dir = createDir();
- long time = dir.lastModified();
+ File topologyDir = new File(dir, "topologies");
+
+ File descriptorsDir = new File(dir, "descriptors");
+ descriptorsDir.mkdirs();
+
+ File sharedProvidersDir = new File(dir, "shared-providers");
+ sharedProvidersDir.mkdirs();
+
+ long time = topologyDir.lastModified();
try {
- createFile(dir, "one.xml", "org/apache/hadoop/gateway/topology/file/topology-one.xml", time);
+ createFile(topologyDir, "one.xml", "org/apache/hadoop/gateway/topology/file/topology-one.xml", time);
TestTopologyListener topoListener = new TestTopologyListener();
FileAlterationMonitor monitor = new FileAlterationMonitor(Long.MAX_VALUE);
@@ -89,17 +103,16 @@ public class DefaultTopologyServiceTest {
Map<String, String> c = new HashMap<>();
GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class);
- EasyMock.expect(config.getGatewayTopologyDir()).andReturn(dir.toString()).anyTimes();
+ EasyMock.expect(config.getGatewayTopologyDir()).andReturn(topologyDir.getAbsolutePath()).anyTimes();
+ EasyMock.expect(config.getGatewayConfDir()).andReturn(descriptorsDir.getParentFile().getAbsolutePath()).anyTimes();
EasyMock.replay(config);
provider.init(config, c);
-
provider.addTopologyChangeListener(topoListener);
provider.reloadTopologies();
-
Collection<Topology> topologies = provider.getTopologies();
assertThat(topologies, notNullValue());
assertThat(topologies.size(), is(1));
@@ -110,7 +123,7 @@ public class DefaultTopologyServiceTest {
topoListener.events.clear();
// Add a file to the directory.
- File two = createFile(dir, "two.xml", "org/apache/hadoop/gateway/topology/file/topology-two.xml", 1L);
+ File two = createFile(topologyDir, "two.xml", "org/apache/hadoop/gateway/topology/file/topology-two.xml", 1L);
provider.reloadTopologies();
topologies = provider.getTopologies();
assertThat(topologies.size(), is(2));
@@ -131,7 +144,7 @@ public class DefaultTopologyServiceTest {
assertThat(event.getTopology(), notNullValue());
// Update a file in the directory.
- two = createFile(dir, "two.xml", "org/apache/hadoop/gateway/topology/file/topology-three.xml", 2L);
+ two = createFile(topologyDir, "two.xml", "org/apache/hadoop/gateway/topology/file/topology-three.xml", 2L);
provider.reloadTopologies();
topologies = provider.getTopologies();
assertThat(topologies.size(), is(2));
@@ -153,6 +166,49 @@ public class DefaultTopologyServiceTest {
topology = topologies.iterator().next();
assertThat(topology.getName(), is("one"));
assertThat(topology.getTimestamp(), is(time));
+
+ // Add a simple descriptor to the descriptors dir to verify topology generation and loading (KNOX-1006)
+ // N.B. This part of the test depends on the DummyServiceDiscovery extension being configured:
+ // org.apache.hadoop.gateway.topology.discovery.test.extension.DummyServiceDiscovery
+ AliasService aliasService = EasyMock.createNiceMock(AliasService.class);
+ EasyMock.expect(aliasService.getPasswordFromAliasForGateway(anyObject(String.class))).andReturn(null).anyTimes();
+ EasyMock.replay(aliasService);
+ DefaultTopologyService.DescriptorsMonitor dm =
+ new DefaultTopologyService.DescriptorsMonitor(topologyDir, aliasService);
+
+ // Write out the referenced provider config first
+ File provCfgFile = createFile(sharedProvidersDir,
+ "ambari-cluster-policy.xml",
+ "org/apache/hadoop/gateway/topology/file/ambari-cluster-policy.xml",
+ 1L);
+ try {
+ // Create the simple descriptor in the descriptors dir
+ File simpleDesc =
+ createFile(descriptorsDir,
+ "four.json",
+ "org/apache/hadoop/gateway/topology/file/simple-topology-four.json",
+ 1L);
+
+ // Trigger the topology generation by noticing the simple descriptor
+ dm.onFileChange(simpleDesc);
+
+ // Load the generated topology
+ provider.reloadTopologies();
+ topologies = provider.getTopologies();
+ assertThat(topologies.size(), is(2));
+ names = new HashSet<>(Arrays.asList("one", "four"));
+ iterator = topologies.iterator();
+ topology = iterator.next();
+ assertThat(names, hasItem(topology.getName()));
+ names.remove(topology.getName());
+ topology = iterator.next();
+ assertThat(names, hasItem(topology.getName()));
+ names.remove(topology.getName());
+ assertThat(names.size(), is(0));
+ } finally {
+ provCfgFile.delete();
+
+ }
} finally {
FileUtils.deleteQuietly(dir);
}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/PropertiesFileServiceDiscoveryTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/PropertiesFileServiceDiscoveryTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/PropertiesFileServiceDiscoveryTest.java
new file mode 100644
index 0000000..269bed2
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/PropertiesFileServiceDiscoveryTest.java
@@ -0,0 +1,90 @@
+/**
+ * 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.hadoop.gateway.topology.discovery;
+
+import org.apache.hadoop.gateway.services.security.impl.DefaultAliasService;
+import org.apache.hadoop.gateway.topology.discovery.test.extension.PropertiesFileServiceDiscoveryType;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.junit.Assert.*;
+
+
+public class PropertiesFileServiceDiscoveryTest {
+
+ private static final Map<String, String> clusterProperties = new HashMap<>();
+ static {
+ clusterProperties.put("mycluster.name", "mycluster");
+ clusterProperties.put("mycluster.NAMENODE", "hdfs://namenodehost:8020");
+ clusterProperties.put("mycluster.JOBTRACKER", "rpc://jobtrackerhostname:8050");
+ clusterProperties.put("mycluster.WEBHCAT", "http://webhcathost:50111/templeton");
+ clusterProperties.put("mycluster.OOZIE", "http://ooziehost:11000/oozie");
+ clusterProperties.put("mycluster.HIVE", "http://hivehostname:10001/clipath");
+ clusterProperties.put("mycluster.RESOURCEMANAGER", "http://remanhost:8088/ws");
+ }
+
+ private static final Properties config = new Properties();
+ static {
+ for (String name : clusterProperties.keySet()) {
+ config.setProperty(name, clusterProperties.get(name));
+ }
+ }
+
+
+ @Test
+ public void testPropertiesFileServiceDiscovery() throws Exception {
+ ServiceDiscovery sd = ServiceDiscoveryFactory.get("PROPERTIES_FILE");
+ assertNotNull(sd);
+
+ String discoveryAddress = this.getClass().getName() + "__test-discovery-source.properties";
+ File discoverySource = new File(discoveryAddress);
+ try {
+ config.store(new FileOutputStream(discoverySource), "Test discovery source for PropertiesFileServiceDiscovery");
+
+ ServiceDiscovery.Cluster c =
+ sd.discover(new DefaultServiceDiscoveryConfig(discoverySource.getAbsolutePath()), "mycluster");
+ assertNotNull(c);
+ for (String name : clusterProperties.keySet()) {
+ assertEquals(clusterProperties.get(name), c.getServiceURLs(name.split("\\.")[1]).get(0));
+ }
+ } finally {
+ discoverySource.delete();
+ }
+ }
+
+
+ private void printServiceURLs(ServiceDiscovery.Cluster cluster, String...services) {
+ for (String name : services) {
+ String value = "";
+ List<String> urls = cluster.getServiceURLs(name);
+ if (urls != null && !urls.isEmpty()) {
+ for (String url : urls) {
+ value += url + " ";
+ }
+ }
+ System.out.println(String.format("%18s: %s", name, value));
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscoveryFactoryTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscoveryFactoryTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscoveryFactoryTest.java
new file mode 100644
index 0000000..d592ede
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscoveryFactoryTest.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.hadoop.gateway.topology.discovery;
+
+import org.apache.hadoop.gateway.services.security.AliasService;
+import org.apache.hadoop.gateway.services.security.impl.DefaultAliasService;
+import org.apache.hadoop.gateway.topology.discovery.test.extension.PropertiesFileServiceDiscoveryType;
+import org.junit.Test;
+
+import java.lang.reflect.Field;
+
+import static org.junit.Assert.*;
+
+
+public class ServiceDiscoveryFactoryTest {
+
+ @Test
+ public void testGetDummyImpl() throws Exception {
+ String TYPE = "DUMMY";
+ ServiceDiscovery sd = ServiceDiscoveryFactory.get(TYPE);
+ assertNotNull("Expected to get a ServiceDiscovery object.", sd);
+ assertEquals("Unexpected ServiceDiscovery type.", TYPE, sd.getType());
+ }
+
+
+ @Test
+ public void testGetDummyImplWithMismatchedCase() throws Exception {
+ String TYPE = "dUmmY";
+ ServiceDiscovery sd = ServiceDiscoveryFactory.get(TYPE);
+ assertNotNull("Expected to get a ServiceDiscovery object.", sd);
+ assertEquals("Unexpected ServiceDiscovery type.", TYPE.toUpperCase(), sd.getType());
+ }
+
+
+ @Test
+ public void testGetInvalidImpl() throws Exception {
+ String TYPE = "InValID";
+ ServiceDiscovery sd = ServiceDiscoveryFactory.get(TYPE);
+ assertNull("Unexpected ServiceDiscovery object.", sd);
+ }
+
+
+ @Test
+ public void testGetImplWithMismatchedType() throws Exception {
+ String TYPE = "DeclaredType";
+ ServiceDiscovery sd = ServiceDiscoveryFactory.get(TYPE);
+ assertNull("Unexpected ServiceDiscovery object.", sd);
+ }
+
+
+ @Test
+ public void testGetPropertiesFileImplWithAliasServiceInjection() throws Exception {
+ String TYPE = "PROPERTIES_FILE";
+ ServiceDiscovery sd = ServiceDiscoveryFactory.get(TYPE, new DefaultAliasService());
+ assertNotNull("Expected to get a ServiceDiscovery object.", sd);
+ assertEquals("Unexpected ServiceDiscovery type.", TYPE, sd.getType());
+
+ // Verify that the AliasService was injected as expected
+ Field aliasServiceField = sd.getClass().getDeclaredField("aliasService");
+ aliasServiceField.setAccessible(true);
+ Object fieldValue = aliasServiceField.get(sd);
+ assertNotNull(fieldValue);
+ assertTrue(AliasService.class.isAssignableFrom(fieldValue.getClass()));
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/DummyServiceDiscovery.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/DummyServiceDiscovery.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/DummyServiceDiscovery.java
new file mode 100644
index 0000000..4a5323e
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/DummyServiceDiscovery.java
@@ -0,0 +1,66 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.gateway.topology.discovery.test.extension;
+
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscovery;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryConfig;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This implementation is intended to be used by tests for which the actual service URLs are of no importance, such that
+ * tests can be written without having a valid service registry (e.g., Ambari) available.
+ */
+public class DummyServiceDiscovery implements ServiceDiscovery {
+
+ static final String TYPE = "DUMMY";
+
+ private static final Cluster DUMMY = new Cluster() {
+ @Override
+ public String getName() {
+ return "dummy";
+ }
+
+ @Override
+ public List<String> getServiceURLs(String serviceName) {
+ return Collections.singletonList("http://servicehost:9999/dummy");
+ }
+ };
+
+ private static final Map<String, Cluster> CLUSTERS = new HashMap<>();
+ static {
+ CLUSTERS.put(DUMMY.getName(), DUMMY);
+ }
+
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+
+ @Override
+ public Map<String, Cluster> discover(ServiceDiscoveryConfig config) {
+ return CLUSTERS;
+ }
+
+ @Override
+ public Cluster discover(ServiceDiscoveryConfig config, String clusterName) {
+ return DUMMY;
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/DummyServiceDiscoveryType.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/DummyServiceDiscoveryType.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/DummyServiceDiscoveryType.java
new file mode 100644
index 0000000..d47c38d
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/DummyServiceDiscoveryType.java
@@ -0,0 +1,32 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.hadoop.gateway.topology.discovery.test.extension;
+
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscovery;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryType;
+
+public class DummyServiceDiscoveryType implements ServiceDiscoveryType {
+ @Override
+ public String getType() {
+ return DummyServiceDiscovery.TYPE;
+ }
+
+ @Override
+ public ServiceDiscovery newInstance() {
+ return new DummyServiceDiscovery();
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/PropertiesFileServiceDiscovery.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/PropertiesFileServiceDiscovery.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/PropertiesFileServiceDiscovery.java
new file mode 100644
index 0000000..a7fc34a
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/PropertiesFileServiceDiscovery.java
@@ -0,0 +1,108 @@
+/**
+ * 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.hadoop.gateway.topology.discovery.test.extension;
+
+import org.apache.hadoop.gateway.services.security.AliasService;
+import org.apache.hadoop.gateway.topology.discovery.GatewayService;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscovery;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryConfig;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.*;
+
+class PropertiesFileServiceDiscovery implements ServiceDiscovery {
+
+ static final String TYPE = "PROPERTIES_FILE";
+
+ @GatewayService
+ AliasService aliasService;
+
+ @Override
+ public String getType() {
+ return TYPE;
+ }
+
+ @Override
+ public Map<String, ServiceDiscovery.Cluster> discover(ServiceDiscoveryConfig config) {
+
+ Map<String, ServiceDiscovery.Cluster> result = new HashMap<>();
+
+ Properties p = new Properties();
+ try {
+ p.load(new FileInputStream(config.getAddress()));
+
+ Map<String, Map<String, List<String>>> clusters = new HashMap<>();
+ for (Object key : p.keySet()) {
+ String propertyKey = (String)key;
+ String[] parts = propertyKey.split("\\.");
+ if (parts.length == 2) {
+ String clusterName = parts[0];
+ String serviceName = parts[1];
+ String serviceURL = p.getProperty(propertyKey);
+ if (!clusters.containsKey(clusterName)) {
+ clusters.put(clusterName, new HashMap<String, List<String>>());
+ }
+ Map<String, List<String>> serviceURLs = clusters.get(clusterName);
+ if (!serviceURLs.containsKey(serviceName)) {
+ serviceURLs.put(serviceName, new ArrayList<String>());
+ }
+ serviceURLs.get(serviceName).add(serviceURL);
+ }
+ }
+
+ for (String clusterName : clusters.keySet()) {
+ result.put(clusterName,
+ new PropertiesFileServiceDiscovery.Cluster(clusterName, clusters.get(clusterName)));
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return result;
+ }
+
+
+ @Override
+ public ServiceDiscovery.Cluster discover(ServiceDiscoveryConfig config, String clusterName) {
+ Map<String, ServiceDiscovery.Cluster> clusters = discover(config);
+ return clusters.get(clusterName);
+ }
+
+
+ static class Cluster implements ServiceDiscovery.Cluster {
+ private String name;
+ private Map<String, List<String>> serviceURLS = new HashMap<>();
+
+ Cluster(String name, Map<String, List<String>> serviceURLs) {
+ this.name = name;
+ this.serviceURLS.putAll(serviceURLs);
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public List<String> getServiceURLs(String serviceName) {
+ return serviceURLS.get(serviceName);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/PropertiesFileServiceDiscoveryType.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/PropertiesFileServiceDiscoveryType.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/PropertiesFileServiceDiscoveryType.java
new file mode 100644
index 0000000..2cfd998
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/PropertiesFileServiceDiscoveryType.java
@@ -0,0 +1,35 @@
+/**
+ * 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.hadoop.gateway.topology.discovery.test.extension;
+
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscovery;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryType;
+
+public class PropertiesFileServiceDiscoveryType implements ServiceDiscoveryType {
+
+ @Override
+ public String getType() {
+ return PropertiesFileServiceDiscovery.TYPE;
+ }
+
+ @Override
+ public ServiceDiscovery newInstance() {
+ return new PropertiesFileServiceDiscovery();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/SneakyServiceDiscoveryImpl.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/SneakyServiceDiscoveryImpl.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/SneakyServiceDiscoveryImpl.java
new file mode 100644
index 0000000..8f7b71a
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/SneakyServiceDiscoveryImpl.java
@@ -0,0 +1,40 @@
+/**
+ * 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.hadoop.gateway.topology.discovery.test.extension;
+
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscovery;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryConfig;
+
+import java.util.Map;
+
+public class SneakyServiceDiscoveryImpl implements ServiceDiscovery {
+ @Override
+ public String getType() {
+ return "ActualType";
+ }
+
+ @Override
+ public Map<String, Cluster> discover(ServiceDiscoveryConfig config) {
+ return null;
+ }
+
+ @Override
+ public Cluster discover(ServiceDiscoveryConfig config, String clusterName) {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/SneakyServiceDiscoveryType.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/SneakyServiceDiscoveryType.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/SneakyServiceDiscoveryType.java
new file mode 100644
index 0000000..97665dc
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/discovery/test/extension/SneakyServiceDiscoveryType.java
@@ -0,0 +1,33 @@
+/**
+ * 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.hadoop.gateway.topology.discovery.test.extension;
+
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscovery;
+import org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryType;
+
+public class SneakyServiceDiscoveryType implements ServiceDiscoveryType {
+ @Override
+ public String getType() {
+ return "DeclaredType";
+ }
+
+ @Override
+ public ServiceDiscovery newInstance() {
+ return new SneakyServiceDiscoveryImpl();
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorFactoryTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorFactoryTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorFactoryTest.java
new file mode 100644
index 0000000..3dac66a
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorFactoryTest.java
@@ -0,0 +1,218 @@
+/**
+ * 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.hadoop.gateway.topology.simple;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.Writer;
+import java.util.*;
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+
+public class SimpleDescriptorFactoryTest {
+
+
+ @Test
+ public void testParseJSONSimpleDescriptor() throws Exception {
+
+ final String discoveryType = "AMBARI";
+ final String discoveryAddress = "http://c6401.ambari.apache.org:8080";
+ final String discoveryUser = "admin";
+ final String providerConfig = "ambari-cluster-policy.xml";
+ final String clusterName = "myCluster";
+
+ final Map<String, List<String>> services = new HashMap<>();
+ services.put("NODEMANAGER", null);
+ services.put("JOBTRACKER", null);
+ services.put("RESOURCEMANAGER", null);
+ services.put("HIVE", Arrays.asList("http://c6401.ambari.apache.org", "http://c6402.ambari.apache.org", "http://c6403.ambari.apache.org"));
+ services.put("AMBARIUI", Arrays.asList("http://c6401.ambari.apache.org:8080"));
+
+ String fileName = "test-topology.json";
+ File testJSON = null;
+ try {
+ testJSON = writeJSON(fileName, discoveryType, discoveryAddress, discoveryUser, providerConfig, clusterName, services);
+ SimpleDescriptor sd = SimpleDescriptorFactory.parse(testJSON.getAbsolutePath());
+ validateSimpleDescriptor(sd, discoveryType, discoveryAddress, providerConfig, clusterName, services);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (testJSON != null) {
+ try {
+ testJSON.delete();
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testParseYAMLSimpleDescriptor() throws Exception {
+
+ final String discoveryType = "AMBARI";
+ final String discoveryAddress = "http://c6401.ambari.apache.org:8080";
+ final String discoveryUser = "joeblow";
+ final String providerConfig = "ambari-cluster-policy.xml";
+ final String clusterName = "myCluster";
+
+ final Map<String, List<String>> services = new HashMap<>();
+ services.put("NODEMANAGER", null);
+ services.put("JOBTRACKER", null);
+ services.put("RESOURCEMANAGER", null);
+ services.put("HIVE", Arrays.asList("http://c6401.ambari.apache.org", "http://c6402.ambari.apache.org", "http://c6403.ambari.apache.org"));
+ services.put("AMBARIUI", Arrays.asList("http://c6401.ambari.apache.org:8080"));
+
+ String fileName = "test-topology.yml";
+ File testYAML = null;
+ try {
+ testYAML = writeYAML(fileName, discoveryType, discoveryAddress, discoveryUser, providerConfig, clusterName, services);
+ SimpleDescriptor sd = SimpleDescriptorFactory.parse(testYAML.getAbsolutePath());
+ validateSimpleDescriptor(sd, discoveryType, discoveryAddress, providerConfig, clusterName, services);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ if (testYAML != null) {
+ try {
+ testYAML.delete();
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+ }
+ }
+
+
+ private void validateSimpleDescriptor(SimpleDescriptor sd,
+ String discoveryType,
+ String discoveryAddress,
+ String providerConfig,
+ String clusterName,
+ Map<String, List<String>> expectedServices) {
+ assertNotNull(sd);
+ assertEquals(discoveryType, sd.getDiscoveryType());
+ assertEquals(discoveryAddress, sd.getDiscoveryAddress());
+ assertEquals(providerConfig, sd.getProviderConfig());
+ assertEquals(clusterName, sd.getClusterName());
+
+ List<SimpleDescriptor.Service> actualServices = sd.getServices();
+
+ assertEquals(expectedServices.size(), actualServices.size());
+
+ for (SimpleDescriptor.Service actualService : actualServices) {
+ assertTrue(expectedServices.containsKey(actualService.getName()));
+ assertEquals(expectedServices.get(actualService.getName()), actualService.getURLs());
+ }
+ }
+
+
+ private File writeJSON(String path, String content) throws Exception {
+ File f = new File(path);
+
+ Writer fw = new FileWriter(f);
+ fw.write(content);
+ fw.flush();
+ fw.close();
+
+ return f;
+ }
+
+
+ private File writeJSON(String path,
+ String discoveryType,
+ String discoveryAddress,
+ String discoveryUser,
+ String providerConfig,
+ String clusterName,
+ Map<String, List<String>> services) throws Exception {
+ File f = new File(path);
+
+ Writer fw = new FileWriter(f);
+ fw.write("{" + "\n");
+ fw.write("\"discovery-type\":\"" + discoveryType + "\",\n");
+ fw.write("\"discovery-address\":\"" + discoveryAddress + "\",\n");
+ fw.write("\"discovery-user\":\"" + discoveryUser + "\",\n");
+ fw.write("\"provider-config-ref\":\"" + providerConfig + "\",\n");
+ fw.write("\"cluster\":\"" + clusterName + "\",\n");
+ fw.write("\"services\":[\n");
+
+ int i = 0;
+ for (String name : services.keySet()) {
+ fw.write("{\"name\":\"" + name + "\"");
+ List<String> urls = services.get(name);
+ if (urls != null) {
+ fw.write(", \"urls\":[");
+ Iterator<String> urlIter = urls.iterator();
+ while (urlIter.hasNext()) {
+ fw.write("\"" + urlIter.next() + "\"");
+ if (urlIter.hasNext()) {
+ fw.write(", ");
+ }
+ }
+ fw.write("]");
+ }
+ fw.write("}");
+ if (i++ < services.size() - 1) {
+ fw.write(",");
+ }
+ fw.write("\n");
+ }
+ fw.write("]\n");
+ fw.write("}\n");
+ fw.flush();
+ fw.close();
+
+ return f;
+ }
+
+ private File writeYAML(String path,
+ String discoveryType,
+ String discoveryAddress,
+ String discoveryUser,
+ String providerConfig,
+ String clusterName,
+ Map<String, List<String>> services) throws Exception {
+ File f = new File(path);
+
+ Writer fw = new FileWriter(f);
+ fw.write("---" + "\n");
+ fw.write("discovery-type: " + discoveryType + "\n");
+ fw.write("discovery-address: " + discoveryAddress + "\n");
+ fw.write("discovery-user: " + discoveryUser + "\n");
+ fw.write("provider-config-ref: " + providerConfig + "\n");
+ fw.write("cluster: " + clusterName+ "\n");
+ fw.write("services:\n");
+ for (String name : services.keySet()) {
+ fw.write(" - name: " + name + "\n");
+ List<String> urls = services.get(name);
+ if (urls != null) {
+ fw.write(" urls:\n");
+ for (String url : urls) {
+ fw.write(" - " + url + "\n");
+ }
+ }
+ }
+ fw.flush();
+ fw.close();
+
+ return f;
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandlerTest.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandlerTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandlerTest.java
new file mode 100644
index 0000000..90c7146
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandlerTest.java
@@ -0,0 +1,239 @@
+/**
+ * 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.hadoop.gateway.topology.simple;
+
+import org.apache.hadoop.gateway.topology.validation.TopologyValidator;
+import org.apache.hadoop.gateway.util.XmlUtils;
+import org.easymock.EasyMock;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathFactory;
+import java.io.*;
+import java.util.*;
+
+import static org.junit.Assert.*;
+
+
+public class SimpleDescriptorHandlerTest {
+
+ private static final String TEST_PROVIDER_CONFIG =
+ " <gateway>\n" +
+ " <provider>\n" +
+ " <role>authentication</role>\n" +
+ " <name>ShiroProvider</name>\n" +
+ " <enabled>true</enabled>\n" +
+ " <param>\n" +
+ " <!-- \n" +
+ " session timeout in minutes, this is really idle timeout,\n" +
+ " defaults to 30mins, if the property value is not defined,, \n" +
+ " current client authentication would expire if client idles contiuosly for more than this value\n" +
+ " -->\n" +
+ " <name>sessionTimeout</name>\n" +
+ " <value>30</value>\n" +
+ " </param>\n" +
+ " <param>\n" +
+ " <name>main.ldapRealm</name>\n" +
+ " <value>org.apache.hadoop.gateway.shirorealm.KnoxLdapRealm</value>\n" +
+ " </param>\n" +
+ " <param>\n" +
+ " <name>main.ldapContextFactory</name>\n" +
+ " <value>org.apache.hadoop.gateway.shirorealm.KnoxLdapContextFactory</value>\n" +
+ " </param>\n" +
+ " <param>\n" +
+ " <name>main.ldapRealm.contextFactory</name>\n" +
+ " <value>$ldapContextFactory</value>\n" +
+ " </param>\n" +
+ " <param>\n" +
+ " <name>main.ldapRealm.userDnTemplate</name>\n" +
+ " <value>uid={0},ou=people,dc=hadoop,dc=apache,dc=org</value>\n" +
+ " </param>\n" +
+ " <param>\n" +
+ " <name>main.ldapRealm.contextFactory.url</name>\n" +
+ " <value>ldap://localhost:33389</value>\n" +
+ " </param>\n" +
+ " <param>\n" +
+ " <name>main.ldapRealm.contextFactory.authenticationMechanism</name>\n" +
+ " <value>simple</value>\n" +
+ " </param>\n" +
+ " <param>\n" +
+ " <name>urls./**</name>\n" +
+ " <value>authcBasic</value>\n" +
+ " </param>\n" +
+ " </provider>\n" +
+ "\n" +
+ " <provider>\n" +
+ " <role>identity-assertion</role>\n" +
+ " <name>Default</name>\n" +
+ " <enabled>true</enabled>\n" +
+ " </provider>\n" +
+ "\n" +
+ " <!--\n" +
+ " Defines rules for mapping host names internal to a Hadoop cluster to externally accessible host names.\n" +
+ " For example, a hadoop service running in AWS may return a response that includes URLs containing the\n" +
+ " some AWS internal host name. If the client needs to make a subsequent request to the host identified\n" +
+ " in those URLs they need to be mapped to external host names that the client Knox can use to connect.\n" +
+ "\n" +
+ " If the external hostname and internal host names are same turn of this provider by setting the value of\n" +
+ " enabled parameter as false.\n" +
+ "\n" +
+ " The name parameter specifies the external host names in a comma separated list.\n" +
+ " The value parameter specifies corresponding internal host names in a comma separated list.\n" +
+ "\n" +
+ " Note that when you are using Sandbox, the external hostname needs to be localhost, as seen in out\n" +
+ " of box sandbox.xml. This is because Sandbox uses port mapping to allow clients to connect to the\n" +
+ " Hadoop services using localhost. In real clusters, external host names would almost never be localhost.\n" +
+ " -->\n" +
+ " <provider>\n" +
+ " <role>hostmap</role>\n" +
+ " <name>static</name>\n" +
+ " <enabled>true</enabled>\n" +
+ " <param><name>localhost</name><value>sandbox,sandbox.hortonworks.com</value></param>\n" +
+ " </provider>\n" +
+ " </gateway>\n";
+
+
+ /**
+ * KNOX-1006
+ *
+ * N.B. This test depends on the DummyServiceDiscovery extension being configured:
+ * org.apache.hadoop.gateway.topology.discovery.test.extension.DummyServiceDiscovery
+ */
+ @Test
+ public void testSimpleDescriptorHandler() throws Exception {
+
+ final String type = "DUMMY";
+ final String address = "http://c6401.ambari.apache.org:8080";
+ final String clusterName = "dummy";
+ final Map<String, List<String>> serviceURLs = new HashMap<>();
+ serviceURLs.put("NAMENODE", null);
+ serviceURLs.put("JOBTRACKER", null);
+ serviceURLs.put("WEBHDFS", null);
+ serviceURLs.put("WEBHCAT", null);
+ serviceURLs.put("OOZIE", null);
+ serviceURLs.put("WEBHBASE", null);
+ serviceURLs.put("HIVE", null);
+ serviceURLs.put("RESOURCEMANAGER", null);
+ serviceURLs.put("AMBARIUI", Arrays.asList("http://c6401.ambari.apache.org:8080"));
+
+ // Write the externalized provider config to a temp file
+ File providerConfig = writeProviderConfig("ambari-cluster-policy.xml", TEST_PROVIDER_CONFIG);
+
+ File topologyFile = null;
+ try {
+ File destDir = (new File(".")).getCanonicalFile();
+
+ // Mock out the simple descriptor
+ SimpleDescriptor testDescriptor = EasyMock.createNiceMock(SimpleDescriptor.class);
+ EasyMock.expect(testDescriptor.getName()).andReturn("mysimpledescriptor").anyTimes();
+ EasyMock.expect(testDescriptor.getDiscoveryAddress()).andReturn(address).anyTimes();
+ EasyMock.expect(testDescriptor.getDiscoveryType()).andReturn(type).anyTimes();
+ EasyMock.expect(testDescriptor.getDiscoveryUser()).andReturn(null).anyTimes();
+ EasyMock.expect(testDescriptor.getProviderConfig()).andReturn(providerConfig.getAbsolutePath()).anyTimes();
+ EasyMock.expect(testDescriptor.getClusterName()).andReturn(clusterName).anyTimes();
+ List<SimpleDescriptor.Service> serviceMocks = new ArrayList<>();
+ for (String serviceName : serviceURLs.keySet()) {
+ SimpleDescriptor.Service svc = EasyMock.createNiceMock(SimpleDescriptor.Service.class);
+ EasyMock.expect(svc.getName()).andReturn(serviceName).anyTimes();
+ EasyMock.expect(svc.getURLs()).andReturn(serviceURLs.get(serviceName)).anyTimes();
+ EasyMock.replay(svc);
+ serviceMocks.add(svc);
+ }
+ EasyMock.expect(testDescriptor.getServices()).andReturn(serviceMocks).anyTimes();
+ EasyMock.replay(testDescriptor);
+
+ // Invoke the simple descriptor handler
+ Map<String, File> files =
+ SimpleDescriptorHandler.handle(testDescriptor,
+ providerConfig.getParentFile(), // simple desc co-located with provider config
+ destDir);
+ topologyFile = files.get("topology");
+
+ // Validate the resulting topology descriptor
+ assertTrue(topologyFile.exists());
+
+ // Validate the topology descriptor's correctness
+ TopologyValidator validator = new TopologyValidator( topologyFile.getAbsolutePath() );
+ if( !validator.validateTopology() ){
+ throw new SAXException( validator.getErrorString() );
+ }
+
+ XPathFactory xPathfactory = XPathFactory.newInstance();
+ XPath xpath = xPathfactory.newXPath();
+
+ // Parse the topology descriptor
+ Document topologyXml = XmlUtils.readXml(topologyFile);
+
+ // Validate the provider configuration
+ Document extProviderConf = XmlUtils.readXml(new ByteArrayInputStream(TEST_PROVIDER_CONFIG.getBytes()));
+ Node gatewayNode = (Node) xpath.compile("/topology/gateway").evaluate(topologyXml, XPathConstants.NODE);
+ assertTrue("Resulting provider config should be identical to the referenced content.",
+ extProviderConf.getDocumentElement().isEqualNode(gatewayNode));
+
+ // Validate the service declarations
+ Map<String, List<String>> topologyServiceURLs = new HashMap<>();
+ NodeList serviceNodes =
+ (NodeList) xpath.compile("/topology/service").evaluate(topologyXml, XPathConstants.NODESET);
+ for (int serviceNodeIndex=0; serviceNodeIndex < serviceNodes.getLength(); serviceNodeIndex++) {
+ Node serviceNode = serviceNodes.item(serviceNodeIndex);
+ Node roleNode = (Node) xpath.compile("role/text()").evaluate(serviceNode, XPathConstants.NODE);
+ assertNotNull(roleNode);
+ String role = roleNode.getNodeValue();
+ NodeList urlNodes = (NodeList) xpath.compile("url/text()").evaluate(serviceNode, XPathConstants.NODESET);
+ for(int urlNodeIndex = 0 ; urlNodeIndex < urlNodes.getLength(); urlNodeIndex++) {
+ Node urlNode = urlNodes.item(urlNodeIndex);
+ assertNotNull(urlNode);
+ String url = urlNode.getNodeValue();
+ assertNotNull("Every declared service should have a URL.", url);
+ if (!topologyServiceURLs.containsKey(role)) {
+ topologyServiceURLs.put(role, new ArrayList<String>());
+ }
+ topologyServiceURLs.get(role).add(url);
+ }
+ }
+ assertEquals("Unexpected number of service declarations.", serviceURLs.size(), topologyServiceURLs.size());
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ } finally {
+ providerConfig.delete();
+ if (topologyFile != null) {
+ topologyFile.delete();
+ }
+ }
+ }
+
+
+ private File writeProviderConfig(String path, String content) throws IOException {
+ File f = new File(path);
+
+ Writer fw = new FileWriter(f);
+ fw.write(content);
+ fw.flush();
+ fw.close();
+
+ return f;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/test/resources/META-INF/services/org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryType
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/resources/META-INF/services/org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryType b/gateway-server/src/test/resources/META-INF/services/org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryType
new file mode 100644
index 0000000..82a6f86
--- /dev/null
+++ b/gateway-server/src/test/resources/META-INF/services/org.apache.hadoop.gateway.topology.discovery.ServiceDiscoveryType
@@ -0,0 +1,21 @@
+##########################################################################
+# 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.
+##########################################################################
+
+org.apache.hadoop.gateway.topology.discovery.test.extension.SneakyServiceDiscoveryType
+org.apache.hadoop.gateway.topology.discovery.test.extension.PropertiesFileServiceDiscoveryType
+org.apache.hadoop.gateway.topology.discovery.test.extension.DummyServiceDiscoveryType
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/test/resources/org/apache/hadoop/gateway/topology/file/ambari-cluster-policy.xml
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/resources/org/apache/hadoop/gateway/topology/file/ambari-cluster-policy.xml b/gateway-server/src/test/resources/org/apache/hadoop/gateway/topology/file/ambari-cluster-policy.xml
new file mode 100644
index 0000000..8223bea
--- /dev/null
+++ b/gateway-server/src/test/resources/org/apache/hadoop/gateway/topology/file/ambari-cluster-policy.xml
@@ -0,0 +1,74 @@
+<gateway>
+ <provider>
+ <role>authentication</role>
+ <name>ShiroProvider</name>
+ <enabled>true</enabled>
+ <param>
+ <!--
+ session timeout in minutes, this is really idle timeout,
+ defaults to 30mins, if the property value is not defined,,
+ current client authentication would expire if client idles contiuosly for more than this value
+ -->
+ <name>sessionTimeout</name>
+ <value>30</value>
+ </param>
+ <param>
+ <name>main.ldapRealm</name>
+ <value>org.apache.hadoop.gateway.shirorealm.KnoxLdapRealm</value>
+ </param>
+ <param>
+ <name>main.ldapContextFactory</name>
+ <value>org.apache.hadoop.gateway.shirorealm.KnoxLdapContextFactory</value>
+ </param>
+ <param>
+ <name>main.ldapRealm.contextFactory</name>
+ <value>$ldapContextFactory</value>
+ </param>
+ <param>
+ <name>main.ldapRealm.userDnTemplate</name>
+ <value>uid={0},ou=people,dc=hadoop,dc=apache,dc=org</value>
+ </param>
+ <param>
+ <name>main.ldapRealm.contextFactory.url</name>
+ <value>ldap://localhost:33389</value>
+ </param>
+ <param>
+ <name>main.ldapRealm.contextFactory.authenticationMechanism</name>
+ <value>simple</value>
+ </param>
+ <param>
+ <name>urls./**</name>
+ <value>authcBasic</value>
+ </param>
+ </provider>
+
+ <provider>
+ <role>identity-assertion</role>
+ <name>Default</name>
+ <enabled>true</enabled>
+ </provider>
+
+ <!--
+ Defines rules for mapping host names internal to a Hadoop cluster to externally accessible host names.
+ For example, a hadoop service running in AWS may return a response that includes URLs containing the
+ some AWS internal host name. If the client needs to make a subsequent request to the host identified
+ in those URLs they need to be mapped to external host names that the client Knox can use to connect.
+
+ If the external hostname and internal host names are same turn of this provider by setting the value of
+ enabled parameter as false.
+
+ The name parameter specifies the external host names in a comma separated list.
+ The value parameter specifies corresponding internal host names in a comma separated list.
+
+ Note that when you are using Sandbox, the external hostname needs to be localhost, as seen in out
+ of box sandbox.xml. This is because Sandbox uses port mapping to allow clients to connect to the
+ Hadoop services using localhost. In real clusters, external host names would almost never be localhost.
+ -->
+ <provider>
+ <role>hostmap</role>
+ <name>static</name>
+ <enabled>true</enabled>
+ <param><name>localhost</name><value>sandbox,sandbox.hortonworks.com</value></param>
+ </provider>
+
+</gateway>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-server/src/test/resources/org/apache/hadoop/gateway/topology/file/simple-topology-four.json
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/resources/org/apache/hadoop/gateway/topology/file/simple-topology-four.json b/gateway-server/src/test/resources/org/apache/hadoop/gateway/topology/file/simple-topology-four.json
new file mode 100644
index 0000000..45407a7
--- /dev/null
+++ b/gateway-server/src/test/resources/org/apache/hadoop/gateway/topology/file/simple-topology-four.json
@@ -0,0 +1,18 @@
+{
+ "discovery-type":"DUMMY",
+ "discovery-address":"http://c6401.ambari.apache.org:8080",
+ "provider-config-ref":"../shared-providers/ambari-cluster-policy.xml",
+ "cluster":"dummy",
+ "services":[
+ {"name":"NAMENODE"},
+ {"name":"JOBTRACKER"},
+ {"name":"WEBHDFS"},
+ {"name":"WEBHCAT"},
+ {"name":"OOZIE"},
+ {"name":"WEBHBASE"},
+ {"name":"HIVE"},
+ {"name":"RESOURCEMANAGER"},
+ {"name":"AMBARI", "urls":["http://c6401.ambari.apache.org:8080"]},
+ {"name":"AMBARIUI", "urls":["http://c6401.ambari.apache.org:8080"]}
+ ]
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/GatewayService.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/GatewayService.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/GatewayService.java
new file mode 100644
index 0000000..554ddbe
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/GatewayService.java
@@ -0,0 +1,29 @@
+/**
+ * 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.hadoop.gateway.topology.discovery;
+
+import java.lang.annotation.*;
+
+/**
+ * This annotation can be used to inject gateway services into a ServiceDiscovery implementation.
+ */
+@Documented
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface GatewayService {
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscovery.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscovery.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscovery.java
new file mode 100644
index 0000000..eefa30b
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscovery.java
@@ -0,0 +1,76 @@
+/**
+ * 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.hadoop.gateway.topology.discovery;
+
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * Implementations provide the means by which Hadoop service endpoint URLs are discovered from a source with knowledge
+ * about the service topology of one or more clusters.
+ */
+public interface ServiceDiscovery {
+
+ /**
+ * This is the type specified in a simple descriptor to indicate which ServiceDiscovery implementation to employ.
+ *
+ * @return The identifier for the service discovery type.
+ */
+ String getType();
+
+
+ /**
+ * Discover details of all the clusters known to the target registry.
+ *
+ * @param config The configuration for the discovery invocation
+ *
+ * @return A Map of the discovered service data, keyed by the cluster name.
+ */
+ Map<String, Cluster> discover(ServiceDiscoveryConfig config);
+
+
+ /**
+ * Discover details for a single cluster.
+ *
+ * @param config The configuration for the discovery invocation
+ * @param clusterName The name of a particular cluster
+ *
+ * @return The discovered service data for the specified cluster
+ */
+ Cluster discover(ServiceDiscoveryConfig config, String clusterName);
+
+
+ /**
+ * A handle to the service discovery result.
+ */
+ interface Cluster {
+
+ /**
+ * @return The name of the cluster
+ */
+ String getName();
+
+ /**
+ * @param serviceName The name of the service
+ * @return The URLs for the specified service in this cluster.
+ */
+ List<String> getServiceURLs(String serviceName);
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscoveryConfig.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscoveryConfig.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscoveryConfig.java
new file mode 100644
index 0000000..6b2e741
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscoveryConfig.java
@@ -0,0 +1,42 @@
+/**
+ * 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.hadoop.gateway.topology.discovery;
+
+/**
+ * ServiceDiscovery configuration details.
+ */
+public interface ServiceDiscoveryConfig {
+
+ /**
+ *
+ * @return The address of the discovery source.
+ */
+ String getAddress();
+
+ /**
+ *
+ * @return The username configured for interactions with the discovery source.
+ */
+ String getUser();
+
+ /**
+ *
+ * @return The alias for the password required for interactions with the discovery source.
+ */
+ String getPasswordAlias();
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscoveryType.java
----------------------------------------------------------------------
diff --git a/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscoveryType.java b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscoveryType.java
new file mode 100644
index 0000000..cddced1
--- /dev/null
+++ b/gateway-spi/src/main/java/org/apache/hadoop/gateway/topology/discovery/ServiceDiscoveryType.java
@@ -0,0 +1,40 @@
+/**
+ * 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.hadoop.gateway.topology.discovery;
+
+/**
+ * ServiceDiscovery extensions must implement this interface to add support for a new discovery source.
+ *
+ * The ServiceLoader mechanism is used to include ServiceDiscovery extensions, and implementations of this interface
+ * are the providers.
+ */
+public interface ServiceDiscoveryType {
+
+ /**
+ *
+ * @return The identifier for the discovery type.
+ */
+ String getType();
+
+
+ /**
+ *
+ * @return A new instance of the ServiceDiscovery implementation provided by this type.
+ */
+ ServiceDiscovery newInstance();
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/c2ca4432/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index d2f4176..2708f6b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -45,6 +45,7 @@
<module>gateway-i18n-logging-log4j</module>
<module>gateway-i18n-logging-sl4j</module>
<module>gateway-spi</module>
+ <module>gateway-discovery-ambari</module>
<module>gateway-server</module>
<module>gateway-server-launcher</module>
<module>gateway-server-xforwarded-filter</module>
@@ -684,6 +685,11 @@
</dependency>
<dependency>
<groupId>${gateway-group}</groupId>
+ <artifactId>gateway-discovery-ambari</artifactId>
+ <version>${gateway-version}</version>
+ </dependency>
+ <dependency>
+ <groupId>${gateway-group}</groupId>
<artifactId>gateway-release</artifactId>
<version>${gateway-version}</version>
</dependency>
@@ -702,17 +708,16 @@
<artifactId>gateway-shell-samples</artifactId>
<version>${gateway-version}</version>
</dependency>
-
- <dependency>
- <groupId>org.picketlink</groupId>
- <artifactId>picketlink-federation</artifactId>
- <version>2.7.0.CR3</version>
- </dependency>
- <dependency>
- <groupId>org.jboss.logging</groupId>
- <artifactId>jboss-logging</artifactId>
- <version>3.2.0.Final</version>
- </dependency>
+ <dependency>
+ <groupId>org.picketlink</groupId>
+ <artifactId>picketlink-federation</artifactId>
+ <version>2.7.0.CR3</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ <version>3.2.0.Final</version>
+ </dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>