You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by sm...@apache.org on 2020/01/15 15:49:19 UTC
[knox] branch master updated: KNOX-2160 - Introducing Hadoop XML
type descriptor format (#236)
This is an automated email from the ASF dual-hosted git repository.
smolnar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git
The following commit(s) were added to refs/heads/master by this push:
new 56726b4 KNOX-2160 - Introducing Hadoop XML type descriptor format (#236)
56726b4 is described below
commit 56726b4f58b8ca96c7756f5b08eab52a28facc86
Author: Sandor Molnar <sm...@apache.org>
AuthorDate: Wed Jan 15 16:49:13 2020 +0100
KNOX-2160 - Introducing Hadoop XML type descriptor format (#236)
---
gateway-cm-integration/pom.xml | 71 ++++++++
.../ClouderaManagerIntegrationMessages.java | 47 +++++
.../ClouderaManagerDescriptorMonitor.java | 98 +++++++++++
.../ClouderaManagerDescriptorParser.java | 190 +++++++++++++++++++++
.../ClouderaManagerDescriptorParserTest.java | 126 ++++++++++++++
.../src/test/resources/testDescriptor.xml | 47 +++++
...onfigurationWithNonHadoopStyleConfiguration.xml | 35 ++++
...tDescriptorConfigurationWithWrongDescriptor.xml | 46 +++++
gateway-release/pom.xml | 8 +
gateway-server/pom.xml | 8 +
.../org/apache/knox/gateway/GatewayServer.java | 4 +
.../gateway/config/impl/GatewayConfigImpl.java | 8 +
.../simple/SimpleDescriptorFactoryTest.java | 2 +-
.../simple/SimpleDescriptorHandlerTest.java | 8 +-
.../apache/knox/gateway/config/GatewayConfig.java | 5 +
.../org/apache/knox/gateway/GatewayTestConfig.java | 5 +
gateway-test/pom.xml | 5 +
.../gateway/SimpleDescriptorHandlerFuncTest.java | 5 +-
gateway-topology-simple/pom.xml | 70 ++++++++
.../discovery/DefaultServiceDiscoveryConfig.java | 0
.../topology/simple/ProviderConfiguration.java | 0
.../simple/ProviderConfigurationParser.java | 0
.../gateway/topology/simple/SimpleDescriptor.java | 10 +-
.../topology/simple/SimpleDescriptorFactory.java | 0
.../topology/simple/SimpleDescriptorHandler.java | 30 ++--
.../topology/simple/SimpleDescriptorImpl.java | 99 ++++++++++-
.../topology/simple/SimpleDescriptorMessages.java | 0
pom.xml | 12 ++
28 files changed, 908 insertions(+), 31 deletions(-)
diff --git a/gateway-cm-integration/pom.xml b/gateway-cm-integration/pom.xml
new file mode 100644
index 0000000..ebe282b
--- /dev/null
+++ b/gateway-cm-integration/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.knox</groupId>
+ <artifactId>gateway</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>gateway-cm-integration</artifactId>
+ <name>gateway-cm-integration</name>
+ <description>Cloudera Manager integration related resources</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.knox</groupId>
+ <artifactId>gateway-i18n</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.knox</groupId>
+ <artifactId>gateway-i18n-logging-log4j</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.knox</groupId>
+ <artifactId>gateway-spi</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.knox</groupId>
+ <artifactId>gateway-topology-simple</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.knox</groupId>
+ <artifactId>gateway-util-common</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.hadoop</groupId>
+ <artifactId>hadoop-auth</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.hadoop</groupId>
+ <artifactId>hadoop-common</artifactId>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/gateway-cm-integration/src/main/java/org/apache/knox/gateway/ClouderaManagerIntegrationMessages.java b/gateway-cm-integration/src/main/java/org/apache/knox/gateway/ClouderaManagerIntegrationMessages.java
new file mode 100644
index 0000000..1312bc8
--- /dev/null
+++ b/gateway-cm-integration/src/main/java/org/apache/knox/gateway/ClouderaManagerIntegrationMessages.java
@@ -0,0 +1,47 @@
+/*
+ * 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;
+
+import org.apache.knox.gateway.i18n.messages.Message;
+import org.apache.knox.gateway.i18n.messages.MessageLevel;
+import org.apache.knox.gateway.i18n.messages.Messages;
+import org.apache.knox.gateway.i18n.messages.StackTrace;
+
+@Messages(logger = "org.apache.knox.gateway")
+public interface ClouderaManagerIntegrationMessages {
+
+ @Message(level = MessageLevel.INFO, text = "Monitoring Cloudera Manager descriptors in {0} ...")
+ void monitoringClouderaManagerDescriptor(String path);
+
+ @Message(level = MessageLevel.INFO, text = "Parsing Cloudera Manager descriptor {0}")
+ void parseClouderaManagerDescriptor(String path);
+
+ @Message(level = MessageLevel.INFO, text = "Found Knox descriptors {0} in {1}")
+ void parsedClouderaManagerDescriptor(String descriptorList, String path);
+
+ @Message(level = MessageLevel.ERROR, text = "Parsing Knox descriptor {0} failed: {1}")
+ void failedToParseDescriptor(String name, String errorMessage, @StackTrace(level = MessageLevel.DEBUG) Exception e);
+
+ @Message(level = MessageLevel.ERROR, text = "Parsing XML configuration {0} failed: {1}")
+ void failedToParseXmlConfiguration(String path, String errorMessage, @StackTrace(level = MessageLevel.DEBUG) Exception e);
+
+ @Message(level = MessageLevel.ERROR, text = "Error while monitoring CM descriptor {0}: {1}")
+ void failedToMonitorClouderaManagerDescriptor(String descriptorPath, String errorMessage, @StackTrace(level = MessageLevel.DEBUG) Exception e);
+
+ @Message(level = MessageLevel.ERROR, text = "Error while producing Knox descriptor: {0}")
+ void failedToProduceKnoxDescriptor(String errorMessage, @StackTrace(level = MessageLevel.DEBUG) Exception e);
+}
diff --git a/gateway-cm-integration/src/main/java/org/apache/knox/gateway/cm/descriptor/ClouderaManagerDescriptorMonitor.java b/gateway-cm-integration/src/main/java/org/apache/knox/gateway/cm/descriptor/ClouderaManagerDescriptorMonitor.java
new file mode 100644
index 0000000..a727839
--- /dev/null
+++ b/gateway-cm-integration/src/main/java/org/apache/knox/gateway/cm/descriptor/ClouderaManagerDescriptorMonitor.java
@@ -0,0 +1,98 @@
+/*
+ * 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.cm.descriptor;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.FileTime;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.filefilter.SuffixFileFilter;
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.apache.knox.gateway.ClouderaManagerIntegrationMessages;
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.util.JsonUtils;
+
+/**
+ * Monitoring KNOX_DESCRIPTOR_DIR for *.cm files - which is a Hadoop XML configuration - and processing those files if they were modified
+ * since the last time it they were processed
+ */
+public class ClouderaManagerDescriptorMonitor {
+
+ private static final String CM_DESCRIPTOR_FILE_EXTENSION = ".cm";
+ private static final ClouderaManagerIntegrationMessages LOG = MessagesFactory.get(ClouderaManagerIntegrationMessages.class);
+ private final String descriptorsDir;
+ private final long monitoringInterval;
+ private final ScheduledExecutorService executorService;
+ private FileTime lastReloadTime;
+
+ public ClouderaManagerDescriptorMonitor(GatewayConfig gatewayConfig) {
+ this.descriptorsDir = gatewayConfig.getGatewayDescriptorsDir();
+ this.monitoringInterval = gatewayConfig.getClouderaManagerDescriptorsMonitoringInterval();
+ this.executorService = Executors.newSingleThreadScheduledExecutor(new BasicThreadFactory.Builder().namingPattern("ClouderaManagerDescriptorMonitor-%d").build());
+ }
+
+ public void setupMonitor() {
+ if (monitoringInterval > 0) {
+ executorService.scheduleAtFixedRate(() -> monitorClouderaManagerDescriptors(), 0, monitoringInterval, TimeUnit.MILLISECONDS);
+ LOG.monitoringClouderaManagerDescriptor(descriptorsDir);
+ }
+ }
+
+ private void monitorClouderaManagerDescriptors() {
+ final File[] clouderaManagerDescriptorFiles = new File(descriptorsDir).listFiles((FileFilter) new SuffixFileFilter(CM_DESCRIPTOR_FILE_EXTENSION));
+ for (File clouderaManagerDescriptorFile : clouderaManagerDescriptorFiles) {
+ monitorClouderaManagerDescriptor(Paths.get(clouderaManagerDescriptorFile.getAbsolutePath()));
+ }
+ }
+
+ private void monitorClouderaManagerDescriptor(Path clouderaManagerDescriptorFile) {
+ try {
+ if (Files.isReadable(clouderaManagerDescriptorFile)) {
+ final FileTime lastModifiedTime = Files.getLastModifiedTime(clouderaManagerDescriptorFile);
+ if (lastReloadTime == null || lastReloadTime.compareTo(lastModifiedTime) < 0) {
+ lastReloadTime = lastModifiedTime;
+ processClouderaManagerDescriptor(clouderaManagerDescriptorFile.toString());
+ }
+ } else {
+ LOG.failedToMonitorClouderaManagerDescriptor(clouderaManagerDescriptorFile.toString(), "File is not readable!", null);
+ }
+ } catch (IOException e) {
+ LOG.failedToMonitorClouderaManagerDescriptor(clouderaManagerDescriptorFile.toString(), e.getMessage(), e);
+ }
+ }
+
+ private void processClouderaManagerDescriptor(String descriptorFilePath) {
+ ClouderaManagerDescriptorParser.parse(descriptorFilePath).forEach(simpleDescriptor -> {
+ try {
+ final File knoxDescriptorFile = new File(descriptorsDir, simpleDescriptor.getName() + ".json");
+ FileUtils.writeStringToFile(knoxDescriptorFile, JsonUtils.renderAsJsonString(simpleDescriptor), StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ LOG.failedToProduceKnoxDescriptor(e.getMessage(), e);
+ }
+ });
+ }
+}
diff --git a/gateway-cm-integration/src/main/java/org/apache/knox/gateway/cm/descriptor/ClouderaManagerDescriptorParser.java b/gateway-cm-integration/src/main/java/org/apache/knox/gateway/cm/descriptor/ClouderaManagerDescriptorParser.java
new file mode 100644
index 0000000..44075fa
--- /dev/null
+++ b/gateway-cm-integration/src/main/java/org/apache/knox/gateway/cm/descriptor/ClouderaManagerDescriptorParser.java
@@ -0,0 +1,190 @@
+/*
+ * 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.cm.descriptor;
+
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.knox.gateway.ClouderaManagerIntegrationMessages;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
+import org.apache.knox.gateway.topology.simple.SimpleDescriptor;
+import org.apache.knox.gateway.topology.simple.SimpleDescriptorImpl;
+import org.apache.knox.gateway.topology.simple.SimpleDescriptorImpl.ApplicationImpl;
+import org.apache.knox.gateway.topology.simple.SimpleDescriptorImpl.ServiceImpl;
+
+public class ClouderaManagerDescriptorParser {
+ private static final ClouderaManagerIntegrationMessages log = MessagesFactory.get(ClouderaManagerIntegrationMessages.class);
+ private static final String CONFIG_NAME_DISCOVERY_TYPE = "discoveryType";
+ private static final String CONFIG_NAME_DISCOVERY_ADDRESS = "discoveryAddress";
+ private static final String CONFIG_NAME_DISCOVERY_USER = "discoveryUser";
+ private static final String CONFIG_NAME_DISCOVERY_PASSWORD_ALIAS = "discoveryPasswordAlias";
+ private static final String CONFIG_NAME_DISCOVERY_CLUSTER = "cluster";
+ private static final String CONFIG_NAME_PROVIDER_CONFIG_REFERENCE = "providerConfigRef";
+ private static final String CONFIG_NAME_APPLICATION_PREFIX = "app";
+ private static final String CONFIG_NAME_SERVICE_URL = "url";
+ private static final String CONFIG_NAME_SERVICE_VERSION = "version";
+
+ /**
+ * Produces a set of {@link SimpleDescriptor}s from the specified file.
+ *
+ * @param path
+ * The path to the configuration file which holds descriptor information in a pre-defined format.
+ * @return A SimpleDescriptor based on the contents of the given file.
+ */
+ public static Set<SimpleDescriptor> parse(String path) {
+ try {
+ log.parseClouderaManagerDescriptor(path);
+ final Configuration xmlConfiguration = new Configuration(false);
+ xmlConfiguration.addResource(Paths.get(path).toUri().toURL());
+ xmlConfiguration.reloadConfiguration();
+ final Set<SimpleDescriptor> descriptors = parseXmlConfig(xmlConfiguration);
+ log.parsedClouderaManagerDescriptor(String.join(", ", descriptors.stream().map(descriptor -> descriptor.getName()).collect(Collectors.toSet())), path);
+ return descriptors;
+ } catch (Exception e) {
+ log.failedToParseXmlConfiguration(path, e.getMessage(), e);
+ return Collections.emptySet();
+ }
+ }
+
+ private static Set<SimpleDescriptor> parseXmlConfig(Configuration xmlConfiguration) {
+ final Set<SimpleDescriptor> descriptors = new LinkedHashSet<>();
+ xmlConfiguration.forEach(xmlDescriptor -> {
+ SimpleDescriptor descriptor = parseXmlDescriptor(xmlDescriptor.getKey(), xmlDescriptor.getValue());
+ if (descriptor != null) {
+ descriptors.add(descriptor);
+ }
+ });
+ return descriptors;
+ }
+
+ private static SimpleDescriptor parseXmlDescriptor(String name, String xmlValue) {
+ try {
+ final SimpleDescriptorImpl descriptor = new SimpleDescriptorImpl();
+ descriptor.setName(name);
+ final String[] configurationPairs = xmlValue.split(";");
+ for (String configurationPair : configurationPairs) {
+ String[] parameterPairParts = configurationPair.trim().split("=", 2);
+ String parameterName = parameterPairParts[0].trim();
+ switch (parameterName) {
+ case CONFIG_NAME_DISCOVERY_TYPE:
+ descriptor.setDiscoveryType(parameterPairParts[1].trim());
+ break;
+ case CONFIG_NAME_DISCOVERY_ADDRESS:
+ descriptor.setDiscoveryAddress(parameterPairParts[1].trim());
+ break;
+ case CONFIG_NAME_DISCOVERY_USER:
+ descriptor.setDiscoveryUser(parameterPairParts[1].trim());
+ break;
+ case CONFIG_NAME_DISCOVERY_PASSWORD_ALIAS:
+ descriptor.setDiscoveryPasswordAlias(parameterPairParts[1].trim());
+ break;
+ case CONFIG_NAME_DISCOVERY_CLUSTER:
+ descriptor.setCluster(parameterPairParts[1].trim());
+ break;
+ case CONFIG_NAME_PROVIDER_CONFIG_REFERENCE:
+ descriptor.setProviderConfig(parameterPairParts[1].trim());
+ break;
+ default:
+ if (parameterName.startsWith(CONFIG_NAME_APPLICATION_PREFIX)) {
+ parseApplication(descriptor, configurationPair.trim());
+ } else {
+ parseService(descriptor, configurationPair.trim());
+ }
+ break;
+ }
+ }
+ return descriptor;
+ } catch(Exception e) {
+ log.failedToParseDescriptor(name, e.getMessage(), e);
+ return null;
+ }
+ }
+
+ /**
+ * An application consists of the following parts: <code>app:$APPLICATION_NAME[:$PARAMETER_NAME=$PARAMETER_VALUE]</code>. Parameters are
+ * optional. <br>
+ * Sample application configurations:
+ * <ul>
+ * <li>app:KNOX</li>
+ * <li>app:knoxauth:param1.name=param1.value</li>
+ * </ul>
+ */
+ private static void parseApplication(SimpleDescriptorImpl descriptor, String configurationPair) {
+ final String[] applicationParts = configurationPair.split(":");
+ final String applicationName = applicationParts[1].trim();
+ ApplicationImpl application = (ApplicationImpl) descriptor.getApplication(applicationName);
+ if (application == null) {
+ application = new ApplicationImpl();
+ descriptor.addApplication(application);
+ application.setName(applicationParts[1]);
+ }
+
+ if (applicationParts.length > 2) {
+ // parameter value may contain ":" (for instance http://host:port) -> considering a parameter name/value pair everything after 'app:$APPLICATION_NAME:'
+ final String applicationParameters = configurationPair.substring(applicationName.length() + 5); // 'app:' and trailing colon takes 5 chars
+ final String[] applicationParameterParts = applicationParameters.split("=", 2);
+ application.addParam(applicationParameterParts[0], applicationParameterParts[1]);
+ }
+ }
+
+ /**
+ * A service consists of the following parts:
+ * <ul>
+ * <li><code>$SERVICE_NAME:url=$URL</code></li>
+ * <li><code>$SERVICE_NAME:version=$VERSION</code> (optional)</li>
+ * <li><code>$SERVICE_NAME[:$PARAMETER_NAME=$PARAMETER_VALUE] (optional)</code></li>
+ * </ul>
+ * Sample application configurations:
+ * <ul>
+ * <li>HIVE:url=http://localhost:123</li>
+ * <li>HIVE:version=1.0</li>
+ * <li>HIVE:param1.name=param1.value</li>
+ * </ul>
+ */
+ private static void parseService(SimpleDescriptorImpl descriptor, String configurationPair) {
+ final String[] serviceParts = configurationPair.split(":");
+ final String serviceName = serviceParts[0].trim();
+ ServiceImpl service = (ServiceImpl) descriptor.getService(serviceName);
+ if (service == null) {
+ service = new ServiceImpl();
+ service.setName(serviceName);
+ descriptor.addService(service);
+ }
+
+ // configuration value may contain ":" (for instance http://host:port) -> considering a configuration name/value pair everything after '$SERVICE_NAME:'
+ final String serviceConfiguration = configurationPair.substring(serviceName.length() + 1).trim();
+ final String[] serviceConfigurationParts = serviceConfiguration.split("=", 2);
+ final String serviceConfigurationName = serviceConfigurationParts[0].trim();
+ final String serviceConfigurationValue = serviceConfigurationParts[1].trim();
+ switch (serviceConfigurationName) {
+ case CONFIG_NAME_SERVICE_URL:
+ service.addUrl(serviceConfigurationValue);
+ break;
+ case CONFIG_NAME_SERVICE_VERSION:
+ service.setVersion(serviceConfigurationValue);
+ break;
+ default:
+ service.addParam(serviceConfigurationName, serviceConfigurationValue);
+ break;
+ }
+ }
+
+}
diff --git a/gateway-cm-integration/src/test/java/org/apache/knox/gateway/cm/descriptor/ClouderaManagerDescriptorParserTest.java b/gateway-cm-integration/src/test/java/org/apache/knox/gateway/cm/descriptor/ClouderaManagerDescriptorParserTest.java
new file mode 100644
index 0000000..84d825f
--- /dev/null
+++ b/gateway-cm-integration/src/test/java/org/apache/knox/gateway/cm/descriptor/ClouderaManagerDescriptorParserTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.cm.descriptor;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.knox.gateway.topology.simple.SimpleDescriptor;
+import org.apache.knox.gateway.topology.simple.SimpleDescriptor.Application;
+import org.apache.knox.gateway.topology.simple.SimpleDescriptor.Service;
+import org.junit.Test;
+
+public class ClouderaManagerDescriptorParserTest {
+
+ @Test
+ public void testXmlParser() throws Exception {
+ final String testConfigPath = this.getClass().getClassLoader().getResource("testDescriptor.xml").getPath();
+ final Set<SimpleDescriptor> descriptors = ClouderaManagerDescriptorParser.parse(testConfigPath);
+ assertEquals(2, descriptors.size());
+ final Iterator<SimpleDescriptor> descriptorsIterator = descriptors.iterator();
+ validateTopology1(descriptorsIterator.next());
+ validateTopology2(descriptorsIterator.next());
+ }
+
+ @Test
+ public void testXmlParserWrongDescriptorContent() throws Exception {
+ final String testConfigPath = this.getClass().getClassLoader().getResource("testDescriptorConfigurationWithWrongDescriptor.xml").getPath();
+ final Set<SimpleDescriptor> descriptors = ClouderaManagerDescriptorParser.parse(testConfigPath);
+ assertEquals(1, descriptors.size());
+ final Iterator<SimpleDescriptor> descriptorsIterator = descriptors.iterator();
+ validateTopology1(descriptorsIterator.next());
+ }
+
+ @Test
+ public void testXmlParserWrongXMLContent() throws Exception {
+ final String testConfigPath = this.getClass().getClassLoader().getResource("testDescriptorConfigurationWithNonHadoopStyleConfiguration.xml").getPath();
+ final Set<SimpleDescriptor> descriptors = ClouderaManagerDescriptorParser.parse(testConfigPath);
+ assertTrue(descriptors.isEmpty());
+ }
+
+ private void validateTopology1(SimpleDescriptor descriptor) {
+ assertEquals("topology1", descriptor.getName());
+ assertEquals("ClouderaManager", descriptor.getDiscoveryType());
+ assertEquals("http://host:123", descriptor.getDiscoveryAddress());
+ assertEquals("user", descriptor.getDiscoveryUser());
+ assertEquals("alias", descriptor.getDiscoveryPasswordAlias());
+ assertEquals("Cluster 1", descriptor.getCluster());
+ assertEquals("topology1-provider", descriptor.getProviderConfig());
+ assertEquals(2, descriptor.getApplications().size());
+
+ assertApplication(descriptor, "knoxauth", Collections.singletonMap("param1.name", "param1.value"));
+ assertApplication(descriptor, "admin-ui", null);
+
+ final Map<String, String> expectedServiceParameters = Stream.of(new String[][] { { "httpclient.connectionTimeout", "5m" }, { "httpclient.socketTimeout", "100m" }, })
+ .collect(Collectors.toMap(data -> data[0], data -> data[1]));
+ assertService(descriptor, "HIVE", "1.0", Collections.singletonList("http://localhost:456"), expectedServiceParameters);
+ }
+
+ private void validateTopology2(SimpleDescriptor descriptor) {
+ assertEquals("topology2", descriptor.getName());
+ assertEquals("Ambari", descriptor.getDiscoveryType());
+ assertEquals("http://host:456", descriptor.getDiscoveryAddress());
+ assertEquals("Cluster 2", descriptor.getCluster());
+ assertEquals("topology2-provider", descriptor.getProviderConfig());
+ assertTrue(descriptor.getApplications().isEmpty());
+
+ final Map<String, String> expectedServiceParameters = Stream.of(new String[][] { { "httpclient.connectionTimeout", "5m" }, { "httpclient.socketTimeout", "100m" }, })
+ .collect(Collectors.toMap(data -> data[0], data -> data[1]));
+ assertService(descriptor, "HDFS", null, Collections.singletonList("http://localhost:456"), expectedServiceParameters);
+ }
+
+ private void assertApplication(SimpleDescriptor descriptor, String expectedApplicationName, Map<String, String> expectedParams) {
+ final Application application = descriptor.getApplication(expectedApplicationName);
+ assertNotNull(application);
+ if (expectedParams != null) {
+ assertTrue(application.getParams().entrySet().containsAll(expectedParams.entrySet()));
+ } else {
+ assertNull(application.getParams());
+ }
+ }
+
+ private void assertService(SimpleDescriptor descriptor, String expectedServiceName, String expectedVersion, List<String> expectedUrls, Map<String, String> expectedParams) {
+ final Service service = descriptor.getService(expectedServiceName);
+ assertNotNull(service);
+ if (expectedVersion != null) {
+ assertEquals(expectedVersion, service.getVersion());
+ } else {
+ assertNull(service.getVersion());
+ }
+
+ if (expectedUrls != null) {
+ assertTrue(service.getURLs().containsAll(expectedUrls));
+ }
+
+ if (expectedParams != null) {
+ assertTrue(service.getParams().entrySet().containsAll(expectedParams.entrySet()));
+ } else {
+ assertNull(service.getParams());
+ }
+ }
+
+}
diff --git a/gateway-cm-integration/src/test/resources/testDescriptor.xml b/gateway-cm-integration/src/test/resources/testDescriptor.xml
new file mode 100644
index 0000000..c853600
--- /dev/null
+++ b/gateway-cm-integration/src/test/resources/testDescriptor.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<configuration>
+ <property>
+ <name>topology1</name>
+ <value>
+ discoveryType=ClouderaManager;
+ discoveryAddress=http://host:123;
+ discoveryUser=user;
+ discoveryPasswordAlias=alias;
+ cluster=Cluster 1;
+ providerConfigRef=topology1-provider;
+ app:knoxauth:param1.name=param1.value;
+ app:admin-ui;
+ HIVE:url=http://localhost:456;
+ HIVE:version=1.0;
+ HIVE:httpclient.connectionTimeout=5m;
+ HIVE:httpclient.socketTimeout=100m
+ </value>
+ </property>
+ <property>
+ <name>topology2</name>
+ <value>
+ discoveryType=Ambari;
+ discoveryAddress=http://host:456;
+ cluster=Cluster 2;
+ providerConfigRef=topology2-provider;
+ HDFS:url=http://localhost:456;
+ HDFS:httpclient.connectionTimeout=5m;
+ HDFS:httpclient.socketTimeout=100m
+ </value>
+ </property>
+</configuration>
\ No newline at end of file
diff --git a/gateway-cm-integration/src/test/resources/testDescriptorConfigurationWithNonHadoopStyleConfiguration.xml b/gateway-cm-integration/src/test/resources/testDescriptorConfigurationWithNonHadoopStyleConfiguration.xml
new file mode 100644
index 0000000..43deb1e
--- /dev/null
+++ b/gateway-cm-integration/src/test/resources/testDescriptorConfigurationWithNonHadoopStyleConfiguration.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<configuration>
+ <config> <!-- should be property -->
+ <name>topology1</name>
+ <value>
+ discoveryType=ClouderaManager;
+ discoveryAddress=http://host:123;
+ discoveryUser=user;
+ discoveryPasswordAlias=alias;
+ cluster=Cluster 1;
+ providerConfigRef=topology1-provider;
+ app:knoxauth:param1.name=param1.value;
+ app:admin-ui;
+ HIVE:url=http://localhost:456;
+ HIVE:version=1.0;
+ HIVE:httpclient.connectionTimeout=5m;
+ HIVE:httpclient.socketTimeout=100m
+ </value>
+ </config>
+</configuration>
\ No newline at end of file
diff --git a/gateway-cm-integration/src/test/resources/testDescriptorConfigurationWithWrongDescriptor.xml b/gateway-cm-integration/src/test/resources/testDescriptorConfigurationWithWrongDescriptor.xml
new file mode 100644
index 0000000..ffa8c25
--- /dev/null
+++ b/gateway-cm-integration/src/test/resources/testDescriptorConfigurationWithWrongDescriptor.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<configuration>
+ <property>
+ <name>topology1</name>
+ <value>
+ discoveryType=ClouderaManager;
+ discoveryAddress=http://host:123;
+ discoveryUser=user;
+ discoveryPasswordAlias=alias;
+ cluster=Cluster 1;
+ providerConfigRef=topology1-provider;
+ app:knoxauth:param1.name=param1.value;
+ app:admin-ui;
+ HIVE:url=http://localhost:456;
+ HIVE:version=1.0;
+ HIVE:httpclient.connectionTimeout=5m;
+ HIVE:httpclient.socketTimeout=100m
+ </value>
+ </property>
+ <property>
+ <name>topology2</name>
+ <value>
+ discoveryType=Ambari;
+ discoveryAddress=http://host:456;
+ cluster=Cluster 2;
+ providerConfigRef=topology2-provider;
+ HDFS:url=http://localhost:456;
+ HDFS <!-- can not be parsed -->
+ </value>
+ </property>
+</configuration>
\ No newline at end of file
diff --git a/gateway-release/pom.xml b/gateway-release/pom.xml
index 2306a3d..24cf45a 100644
--- a/gateway-release/pom.xml
+++ b/gateway-release/pom.xml
@@ -425,5 +425,13 @@
<groupId>org.apache.knox</groupId>
<artifactId>gateway-service-hashicorp-vault</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.knox</groupId>
+ <artifactId>gateway-topology-simple</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.knox</groupId>
+ <artifactId>gateway-cm-integration</artifactId>
+ </dependency>
</dependencies>
</project>
diff --git a/gateway-server/pom.xml b/gateway-server/pom.xml
index 2924c22..ed3b7d6 100644
--- a/gateway-server/pom.xml
+++ b/gateway-server/pom.xml
@@ -67,6 +67,10 @@
</dependency>
<dependency>
<groupId>org.apache.knox</groupId>
+ <artifactId>gateway-cm-integration</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.knox</groupId>
<artifactId>gateway-i18n</artifactId>
</dependency>
<dependency>
@@ -91,6 +95,10 @@
</dependency>
<dependency>
<groupId>org.apache.knox</groupId>
+ <artifactId>gateway-topology-simple</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.knox</groupId>
<artifactId>gateway-util-common</artifactId>
</dependency>
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
index 7628cf7..82c8bbb 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/GatewayServer.java
@@ -27,6 +27,7 @@ import org.apache.knox.gateway.audit.api.AuditServiceFactory;
import org.apache.knox.gateway.audit.api.Auditor;
import org.apache.knox.gateway.audit.api.ResourceType;
import org.apache.knox.gateway.audit.log4j.audit.AuditConstants;
+import org.apache.knox.gateway.cm.descriptor.ClouderaManagerDescriptorMonitor;
import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.config.GatewayConfigurationException;
import org.apache.knox.gateway.config.impl.GatewayConfigImpl;
@@ -621,6 +622,9 @@ public class GatewayServer {
"org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration" );
+ final ClouderaManagerDescriptorMonitor cmDescriptorMonitor = new ClouderaManagerDescriptorMonitor(config);
+ cmDescriptorMonitor.setupMonitor();
+
// Load the current topologies.
// Redeploy autodeploy topologies.
File topologiesDir = calculateAbsoluteTopologiesDir();
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
index 19741c8..6c1ccaa 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java
@@ -240,6 +240,9 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {
/* property that specifies list of services for which we need to append service name to the X-Forward-Context header */
public static final String X_FORWARD_CONTEXT_HEADER_APPEND_SERVICES = GATEWAY_CONFIG_FILE_PREFIX + ".xforwarded.header.context.append.servicename";
+ private static final String CLOUDERA_MANAGER_DESCRIPTORS_MONITOR_INTERVAL = GATEWAY_CONFIG_FILE_PREFIX + ".cloudera.manager.descriptors.monitor.interval";
+ private static final long DEFAULT_CLOUDERA_MANAGER_DESCRIPTORS_MONITOR_INTERVAL = 30000L;
+
public GatewayConfigImpl() {
init();
}
@@ -1094,4 +1097,9 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig {
return set;
}
+
+ @Override
+ public long getClouderaManagerDescriptorsMonitoringInterval() {
+ return getLong(CLOUDERA_MANAGER_DESCRIPTORS_MONITOR_INTERVAL, DEFAULT_CLOUDERA_MANAGER_DESCRIPTORS_MONITOR_INTERVAL);
+ }
}
diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactoryTest.java b/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactoryTest.java
index 52cc6ee..cca10e0 100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactoryTest.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactoryTest.java
@@ -755,7 +755,7 @@ public class SimpleDescriptorFactoryTest {
assertEquals(discoveryType, sd.getDiscoveryType());
assertEquals(discoveryAddress, sd.getDiscoveryAddress());
assertEquals(providerConfig, sd.getProviderConfig());
- assertEquals(clusterName, sd.getClusterName());
+ assertEquals(clusterName, sd.getCluster());
List<SimpleDescriptor.Service> actualServices = sd.getServices();
diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandlerTest.java b/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandlerTest.java
index f5aca6a..4a6bc13 100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandlerTest.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandlerTest.java
@@ -199,7 +199,7 @@ public class SimpleDescriptorHandlerTest {
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();
+ EasyMock.expect(testDescriptor.getCluster()).andReturn(clusterName).anyTimes();
List<SimpleDescriptor.Service> serviceMocks = new ArrayList<>();
for (String serviceName : serviceURLs.keySet()) {
SimpleDescriptor.Service svc = EasyMock.createNiceMock(SimpleDescriptor.Service.class);
@@ -377,7 +377,7 @@ public class SimpleDescriptorHandlerTest {
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(CLUSTER_NAME).anyTimes();
+ EasyMock.expect(testDescriptor.getCluster()).andReturn(CLUSTER_NAME).anyTimes();
List<SimpleDescriptor.Service> serviceMocks = new ArrayList<>();
for (String serviceName : serviceURLs.keySet()) {
SimpleDescriptor.Service svc = EasyMock.createNiceMock(SimpleDescriptor.Service.class);
@@ -580,7 +580,7 @@ public class SimpleDescriptorHandlerTest {
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();
+ EasyMock.expect(testDescriptor.getCluster()).andReturn(clusterName).anyTimes();
List<SimpleDescriptor.Service> serviceMocks = new ArrayList<>();
for (String serviceName : serviceURLs.keySet()) {
SimpleDescriptor.Service svc = EasyMock.createNiceMock(SimpleDescriptor.Service.class);
@@ -781,7 +781,7 @@ public class SimpleDescriptorHandlerTest {
EasyMock.expect(testDescriptor.getDiscoveryAddress()).andReturn(discoveryConfig.getAbsolutePath()).anyTimes();
EasyMock.expect(testDescriptor.getDiscoveryType()).andReturn("PROPERTIES_FILE").anyTimes();
EasyMock.expect(testDescriptor.getDiscoveryUser()).andReturn(null).anyTimes();
- EasyMock.expect(testDescriptor.getClusterName()).andReturn(clusterName).anyTimes();
+ EasyMock.expect(testDescriptor.getCluster()).andReturn(clusterName).anyTimes();
final SimpleDescriptor.Service knoxService = EasyMock.createNiceMock(SimpleDescriptor.Service.class);
EasyMock.expect(knoxService.getName()).andReturn("KNOX").anyTimes();
diff --git a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
index 52a62cc..94e7642 100644
--- a/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
+++ b/gateway-spi/src/main/java/org/apache/knox/gateway/config/GatewayConfig.java
@@ -642,4 +642,9 @@ public interface GatewayConfig {
* @return a set of service principal names that indicate which services to ignore doAs request
*/
Set<String> getServicesToIgnoreDoAs();
+
+ /**
+ * @return the monitoring interval (in milliseconds) of Cloudera Manager descriptors
+ */
+ long getClouderaManagerDescriptorsMonitoringInterval();
}
diff --git a/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java b/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
index 4a2c754..6170550 100644
--- a/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
+++ b/gateway-test-release-utils/src/main/java/org/apache/knox/gateway/GatewayTestConfig.java
@@ -764,4 +764,9 @@ public class GatewayTestConfig extends Configuration implements GatewayConfig {
public Set<String> getServicesToIgnoreDoAs() {
return null;
}
+
+ @Override
+ public long getClouderaManagerDescriptorsMonitoringInterval() {
+ return 0;
+ }
}
diff --git a/gateway-test/pom.xml b/gateway-test/pom.xml
index a215525..257e5a6 100644
--- a/gateway-test/pom.xml
+++ b/gateway-test/pom.xml
@@ -102,6 +102,11 @@
</dependency>
<dependency>
<groupId>org.apache.knox</groupId>
+ <artifactId>gateway-topology-simple</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.knox</groupId>
<artifactId>gateway-release</artifactId>
<scope>test</scope>
</dependency>
diff --git a/gateway-test/src/test/java/org/apache/knox/gateway/SimpleDescriptorHandlerFuncTest.java b/gateway-test/src/test/java/org/apache/knox/gateway/SimpleDescriptorHandlerFuncTest.java
index 87eea0b..3c53699 100644
--- a/gateway-test/src/test/java/org/apache/knox/gateway/SimpleDescriptorHandlerFuncTest.java
+++ b/gateway-test/src/test/java/org/apache/knox/gateway/SimpleDescriptorHandlerFuncTest.java
@@ -150,7 +150,7 @@ public class SimpleDescriptorHandlerFuncTest {
EasyMock.expect(testDescriptor.getDiscoveryType()).andReturn(discoveryType).anyTimes();
EasyMock.expect(testDescriptor.getDiscoveryUser()).andReturn(null).anyTimes();
EasyMock.expect(testDescriptor.getProviderConfig()).andReturn(providerConfig.getAbsolutePath()).anyTimes();
- EasyMock.expect(testDescriptor.getClusterName()).andReturn(clusterName).anyTimes();
+ EasyMock.expect(testDescriptor.getCluster()).andReturn(clusterName).anyTimes();
List<SimpleDescriptor.Service> serviceMocks = new ArrayList<>();
for (String serviceName : serviceURLs.keySet()) {
SimpleDescriptor.Service svc = EasyMock.createNiceMock(SimpleDescriptor.Service.class);
@@ -231,7 +231,8 @@ public class SimpleDescriptorHandlerFuncTest {
Map<String, File> files = SimpleDescriptorHandler.handle(config,
testDescriptor,
providerConfig.getParentFile(),
- destDir);
+ destDir,
+ GatewayServer.getGatewayServices());
topologyFile = files.get("topology");
// Validate the AliasService interaction
diff --git a/gateway-topology-simple/pom.xml b/gateway-topology-simple/pom.xml
new file mode 100644
index 0000000..53f5c97
--- /dev/null
+++ b/gateway-topology-simple/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.knox</groupId>
+ <artifactId>gateway</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>gateway-topology-simple</artifactId>
+ <name>gateway-topology-simple</name>
+ <description>Simple topology generation (based on provider/descriptor pairs) related resources</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.knox</groupId>
+ <artifactId>gateway-i18n</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.knox</groupId>
+ <artifactId>gateway-spi</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-annotations</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.dataformat</groupId>
+ <artifactId>jackson-dataformat-yaml</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>javax.xml.bind</groupId>
+ <artifactId>jaxb-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.hadoop</groupId>
+ <artifactId>hadoop-common</artifactId>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/topology/discovery/DefaultServiceDiscoveryConfig.java b/gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/discovery/DefaultServiceDiscoveryConfig.java
similarity index 100%
rename from gateway-server/src/main/java/org/apache/knox/gateway/topology/discovery/DefaultServiceDiscoveryConfig.java
rename to gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/discovery/DefaultServiceDiscoveryConfig.java
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/ProviderConfiguration.java b/gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/ProviderConfiguration.java
similarity index 100%
rename from gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/ProviderConfiguration.java
rename to gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/ProviderConfiguration.java
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/ProviderConfigurationParser.java b/gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/ProviderConfigurationParser.java
similarity index 100%
rename from gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/ProviderConfigurationParser.java
rename to gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/ProviderConfigurationParser.java
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptor.java b/gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptor.java
similarity index 81%
rename from gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptor.java
rename to gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptor.java
index 51a121c..5b32662 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptor.java
+++ b/gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptor.java
@@ -19,6 +19,9 @@ package org.apache.knox.gateway.topology.simple;
import java.util.List;
import java.util.Map;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+
+
public interface SimpleDescriptor {
String getName();
@@ -31,15 +34,19 @@ public interface SimpleDescriptor {
String getDiscoveryPasswordAlias();
- String getClusterName();
+ String getCluster();
String getProviderConfig();
List<Service> getServices();
+ Service getService(String serviceName);
+
List<Application> getApplications();
+ Application getApplication(String applicationName);
+ @JsonDeserialize(as = SimpleDescriptorImpl.ServiceImpl.class)
interface Service {
String getName();
@@ -50,6 +57,7 @@ public interface SimpleDescriptor {
List<String> getURLs();
}
+ @JsonDeserialize(as = SimpleDescriptorImpl.ApplicationImpl.class)
interface Application {
String getName();
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactory.java b/gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactory.java
similarity index 100%
rename from gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactory.java
rename to gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorFactory.java
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java b/gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java
similarity index 97%
rename from gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java
rename to gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java
index 70bf3a2..5d68313 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java
+++ b/gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java
@@ -16,7 +16,6 @@
*/
package org.apache.knox.gateway.topology.simple;
-import org.apache.knox.gateway.GatewayServer;
import org.apache.knox.gateway.config.GatewayConfig;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
import org.apache.knox.gateway.services.ServiceType;
@@ -87,18 +86,6 @@ public class SimpleDescriptorHandler {
private static final Set<String> ALLOWED_SERVICES_WITHOUT_URLS_AND_PARAMS = Collections.singleton("KNOX");
- public static Map<String, File> handle(GatewayConfig config, File desc) throws IOException {
- return handle(config, desc, NO_GATEWAY_SERVICES);
- }
-
- public static Map<String, File> handle(GatewayConfig config, File desc, Service...gatewayServices) throws IOException {
- return handle(config, desc, desc.getParentFile(), gatewayServices);
- }
-
- public static Map<String, File> handle(GatewayConfig config, File desc, File destDirectory) throws IOException {
- return handle(config, desc, destDirectory, NO_GATEWAY_SERVICES);
- }
-
public static Map<String, File> handle(GatewayConfig config, File desc, File destDirectory, Service...gatewayServices) throws IOException {
return handle(config, SimpleDescriptorFactory.parse(desc.getAbsolutePath()), desc.getParentFile(), destDirectory, gatewayServices);
}
@@ -185,7 +172,7 @@ public class SimpleDescriptorHandler {
// when the topology is deployed. This is to support Knox HA deployments, where multiple Knox instances are
// generating topologies based on a shared remote descriptor, and they must all be able to encrypt/decrypt
// query params with the same credentials. (KNOX-1136)
- if (!provisionQueryParamEncryptionCredential(desc.getName())) {
+ if (!provisionQueryParamEncryptionCredential(desc.getName(), getGatewayServices(gatewayServices))) {
log.unableCreatePasswordForEncryption(desc.getName());
}
@@ -201,6 +188,14 @@ public class SimpleDescriptorHandler {
serviceParams);
}
+ private static GatewayServices getGatewayServices(Service... services) {
+ for (Service service : services) {
+ if (service instanceof GatewayServices) {
+ return (GatewayServices) service;
+ }
+ }
+ return null;
+ }
private static ServiceDiscovery.Cluster performDiscovery(GatewayConfig config, SimpleDescriptor desc, Service...gatewayServices) {
DefaultServiceDiscoveryConfig sdc = new DefaultServiceDiscoveryConfig(desc.getDiscoveryAddress());
@@ -220,7 +215,7 @@ public class SimpleDescriptorHandler {
discoveryInstances.put(discoveryType, sd);
}
- return sd.discover(config, sdc, desc.getClusterName());
+ return sd.discover(config, sdc, desc.getCluster());
}
@@ -253,11 +248,10 @@ public class SimpleDescriptorHandler {
*
* @return true if the credential was successfully provisioned; otherwise, false.
*/
- private static boolean provisionQueryParamEncryptionCredential(final String topologyName) {
+ private static boolean provisionQueryParamEncryptionCredential(final String topologyName, final GatewayServices services) {
boolean result = false;
try {
- GatewayServices services = GatewayServer.getGatewayServices();
if (services != null) {
MasterService ms = services.getService(ServiceType.MASTER_SERVICE);
if (ms != null) {
@@ -574,7 +568,7 @@ public class SimpleDescriptorHandler {
// Write the generated content to a file
String topologyFilename = desc.getName();
if (topologyFilename == null) {
- topologyFilename = desc.getClusterName();
+ topologyFilename = desc.getCluster();
}
topologyDescriptor = new File(destDirectory, topologyFilename + ".xml");
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorImpl.java b/gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorImpl.java
similarity index 59%
rename from gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorImpl.java
rename to gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorImpl.java
index 535e1a9..e8ed738 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorImpl.java
+++ b/gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorImpl.java
@@ -22,8 +22,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.TreeMap;
-class SimpleDescriptorImpl implements SimpleDescriptor {
+public class SimpleDescriptorImpl implements SimpleDescriptor {
@JsonProperty("discovery-type")
private String discoveryType;
@@ -44,14 +45,14 @@ class SimpleDescriptorImpl implements SimpleDescriptor {
private String cluster;
@JsonProperty("services")
- private List<ServiceImpl> services;
+ private List<Service> services;
@JsonProperty("applications")
- private List<ApplicationImpl> applications;
+ private List<Application> applications;
private String name;
- void setName(String name) {
+ public void setName(String name) {
this.name = name;
}
@@ -60,36 +61,67 @@ class SimpleDescriptorImpl implements SimpleDescriptor {
return name;
}
+ public void setDiscoveryType(String discoveryType) {
+ this.discoveryType = discoveryType;
+ }
+
@Override
public String getDiscoveryType() {
return discoveryType;
}
+ public void setDiscoveryAddress(String discoveryAddress) {
+ this.discoveryAddress = discoveryAddress;
+ }
+
@Override
public String getDiscoveryAddress() {
return discoveryAddress;
}
+ public void setDiscoveryUser(String discoveryUser) {
+ this.discoveryUser = discoveryUser;
+ }
+
@Override
public String getDiscoveryUser() {
return discoveryUser;
}
+ public void setDiscoveryPasswordAlias(String discoveryPasswordAlias) {
+ this.discoveryPasswordAlias = discoveryPasswordAlias;
+ }
+
@Override
public String getDiscoveryPasswordAlias() {
return discoveryPasswordAlias;
}
+ public void setCluster(String cluster) {
+ this.cluster = cluster;
+ }
+
@Override
- public String getClusterName() {
+ public String getCluster() {
return cluster;
}
+ public void setProviderConfig(String providerConfig) {
+ this.providerConfig = providerConfig;
+ }
+
@Override
public String getProviderConfig() {
return providerConfig;
}
+ public void addService(Service service) {
+ if (services == null) {
+ services = new ArrayList<>();
+ }
+ services.add(service);
+ }
+
@Override
public List<Service> getServices() {
List<Service> result = new ArrayList<>();
@@ -100,6 +132,18 @@ class SimpleDescriptorImpl implements SimpleDescriptor {
}
@Override
+ public Service getService(String serviceName) {
+ return getServices().stream().filter(service -> service.getName().equals(serviceName)).findFirst().orElse(null);
+ }
+
+ public void addApplication(Application application) {
+ if (applications == null) {
+ applications = new ArrayList<>();
+ }
+ applications.add(application);
+ }
+
+ @Override
public List<Application> getApplications() {
List<Application> result = new ArrayList<>();
if (applications != null) {
@@ -108,6 +152,11 @@ class SimpleDescriptorImpl implements SimpleDescriptor {
return result;
}
+ @Override
+ public Application getApplication(String applicationName) {
+ return getApplications().stream().filter(application -> application.getName().equals(applicationName)).findFirst().orElse(null);
+ }
+
public static class ServiceImpl implements Service {
@JsonProperty("name")
private String name;
@@ -140,6 +189,28 @@ class SimpleDescriptorImpl implements SimpleDescriptor {
public List<String> getURLs() {
return urls;
}
+
+ public void addUrl(String url) {
+ if (this.urls == null) {
+ this.urls = new ArrayList<>();
+ }
+ this.urls.add(url);
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public void addParam(String name, String value) {
+ if (this.params == null) {
+ this.params = new TreeMap<>();
+ }
+ this.params.put(name, value);
+ }
}
public static class ApplicationImpl implements Application {
@@ -166,6 +237,24 @@ class SimpleDescriptorImpl implements SimpleDescriptor {
public List<String> getURLs() {
return urls;
}
+
+ public void addUrl(String url) {
+ if (this.urls == null) {
+ this.urls = new ArrayList<>();
+ }
+ this.urls.add(url);
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public void addParam(String name, String value) {
+ if (this.params == null) {
+ this.params = new TreeMap<>();
+ }
+ this.params.put(name, value);
+ }
}
}
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorMessages.java b/gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorMessages.java
similarity index 100%
rename from gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorMessages.java
rename to gateway-topology-simple/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorMessages.java
diff --git a/pom.xml b/pom.xml
index 8b8f673..6ebae0f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -137,6 +137,8 @@
<module>gateway-docker</module>
<module>gateway-service-hashicorp-vault</module>
<module>gateway-release-common</module>
+ <module>gateway-topology-simple</module>
+ <module>gateway-cm-integration</module>
</modules>
<properties>
@@ -1153,6 +1155,16 @@
<artifactId>gateway-release-common</artifactId>
<version>${project.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.knox</groupId>
+ <artifactId>gateway-topology-simple</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.knox</groupId>
+ <artifactId>gateway-cm-integration</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>