You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by pz...@apache.org on 2018/02/01 23:43:56 UTC
[2/2] knox git commit: KNOX-1153 - Service-level overrides for HA
provider configuration in generated topologies,
and alternate provide config formats.
KNOX-1153 - Service-level overrides for HA provider configuration in generated topologies, and alternate provide config formats.
Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/7025086a
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/7025086a
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/7025086a
Branch: refs/heads/master
Commit: 7025086a8a0ab757cb24486b27515f8f5331bfa0
Parents: 0deafca
Author: Phil Zampino <pz...@apache.org>
Authored: Thu Feb 1 18:40:53 2018 -0500
Committer: Phil Zampino <pz...@apache.org>
Committed: Thu Feb 1 18:40:53 2018 -0500
----------------------------------------------------------------------
.../discovery/ambari/AmbariCluster.java | 100 ++++-
.../ambari/AmbariServiceDiscoveryMessages.java | 4 +
.../discovery/ambari/WebHdfsUrlCreator.java | 45 +-
...rvice-discovery-zk-config-mapping.properties | 50 +++
.../discovery/ambari/AmbariClusterTest.java | 150 +++++++
.../deploy/HaProviderDeploymentContributor.java | 68 ++-
.../HaProviderDeploymentContributorTest.java | 365 ++++++++++++++++
.../topology/impl/DefaultTopologyService.java | 15 +-
.../topology/simple/ProviderConfiguration.java | 39 ++
.../simple/ProviderConfigurationParser.java | 260 ++++++++++++
.../simple/SimpleDescriptorHandler.java | 425 ++++++++++++-------
.../simple/SimpleDescriptorMessages.java | 9 +-
.../test/extension/DummyServiceDiscovery.java | 5 +
.../PropertiesFileServiceDiscovery.java | 5 +
.../simple/ProviderConfigurationParserTest.java | 336 +++++++++++++++
.../simple/SimpleDescriptorHandlerTest.java | 199 +++++----
.../topology/discovery/ServiceDiscovery.java | 15 +
17 files changed, 1830 insertions(+), 260 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/knox/blob/7025086a/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariCluster.java
----------------------------------------------------------------------
diff --git a/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariCluster.java b/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariCluster.java
index 9d3fa74..2a1db09 100644
--- a/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariCluster.java
+++ b/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariCluster.java
@@ -16,22 +16,64 @@
*/
package org.apache.knox.gateway.topology.discovery.ambari;
+import org.apache.knox.gateway.i18n.messages.MessagesFactory;
import org.apache.knox.gateway.topology.discovery.ServiceDiscovery;
+import java.io.FileInputStream;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Properties;
class AmbariCluster implements ServiceDiscovery.Cluster {
- private String name = null;
+ private static final AmbariServiceDiscoveryMessages log = MessagesFactory.get(AmbariServiceDiscoveryMessages.class);
+
+ private static final String ZK_CONFIG_MAPPING_FILE = "ambari-service-discovery-zk-config-mapping.properties";
+
+ static final String ZK_CONFIG_MAPPING_SYSTEM_PROPERTY =
+ "org.apache.knox.gateway.topology.discovery.ambari.zk.mapping";
+
+ // Mapping of service roles to Hadoop service configurations and ZooKeeper property names
+ private static final Properties zooKeeperHAConfigMappings = new Properties();
+ static {
+ try {
+ // Load all the default mappings
+ Properties defaults = new Properties();
+ defaults.load(AmbariServiceDiscovery.class.getClassLoader().getResourceAsStream(ZK_CONFIG_MAPPING_FILE));
+ for (String name : defaults.stringPropertyNames()) {
+ zooKeeperHAConfigMappings.setProperty(name, defaults.getProperty(name));
+ }
+
+ // Attempt to apply overriding or additional mappings
+ String overridesPath = System.getProperty(ZK_CONFIG_MAPPING_SYSTEM_PROPERTY);
+ if (overridesPath != null) {
+ Properties overrides = new Properties();
+ InputStream in = new FileInputStream(overridesPath);
+ try {
+ overrides.load(in);
+ } finally {
+ in.close();
+ }
+
+ for (String name : overrides.stringPropertyNames()) {
+ zooKeeperHAConfigMappings.setProperty(name, overrides.getProperty(name));
+ }
+ }
+ } catch (Exception e) {
+ log.failedToLoadZooKeeperConfigurationMapping(e);
+ }
+ }
+
+ private String name;
private ServiceURLFactory urlFactory;
private Map<String, Map<String, ServiceConfiguration>> serviceConfigurations = new HashMap<>();
- private Map<String, AmbariComponent> components = null;
+ private Map<String, AmbariComponent> components;
AmbariCluster(String name) {
@@ -91,6 +133,33 @@ class AmbariCluster implements ServiceDiscovery.Cluster {
return urls;
}
+ @Override
+ public ZooKeeperConfig getZooKeeperConfiguration(String serviceName) {
+ ZooKeeperConfig result = null;
+
+ String config = zooKeeperHAConfigMappings.getProperty(serviceName + ".config");
+ if (config != null) {
+ String[] parts = config.split(":");
+ if (parts.length == 2) {
+ ServiceConfiguration sc = getServiceConfiguration(parts[0], parts[1]);
+ if (sc != null) {
+ String enabledProp = zooKeeperHAConfigMappings.getProperty(serviceName + ".enabled");
+ String ensembleProp = zooKeeperHAConfigMappings.getProperty(serviceName + ".ensemble");
+ String namespaceProp = zooKeeperHAConfigMappings.getProperty(serviceName + ".namespace");
+ Map<String, String> scProps = sc.getProperties();
+ if (scProps != null) {
+ result =
+ new ZooKeeperConfiguration(enabledProp != null ? scProps.get(enabledProp) : null,
+ ensembleProp != null ? scProps.get(ensembleProp) : null,
+ namespaceProp != null ? scProps.get(namespaceProp) : null);
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
static class ServiceConfiguration {
@@ -117,4 +186,31 @@ class AmbariCluster implements ServiceDiscovery.Cluster {
}
}
+
+ static class ZooKeeperConfiguration implements ServiceDiscovery.Cluster.ZooKeeperConfig {
+ boolean isEnabled;
+ String ensemble;
+ String namespace;
+
+ ZooKeeperConfiguration(String enabled, String ensemble, String namespace) {
+ this.namespace = namespace;
+ this.ensemble = ensemble;
+ this.isEnabled = (enabled != null ? Boolean.valueOf(enabled) : true);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return isEnabled;
+ }
+
+ @Override
+ public String getEnsemble() {
+ return ensemble;
+ }
+
+ @Override
+ public String getNamespace() {
+ return namespace;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/knox/blob/7025086a/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariServiceDiscoveryMessages.java
----------------------------------------------------------------------
diff --git a/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariServiceDiscoveryMessages.java b/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariServiceDiscoveryMessages.java
index 12e6078..ffd04a9 100644
--- a/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariServiceDiscoveryMessages.java
+++ b/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariServiceDiscoveryMessages.java
@@ -49,6 +49,10 @@ public interface AmbariServiceDiscoveryMessages {
void failedToLoadServiceDiscoveryURLDefConfiguration(@StackTrace(level = MessageLevel.DEBUG) Exception e);
@Message(level = MessageLevel.ERROR,
+ text = "Failed to load ZooKeeper configuration property mappings: {1}")
+ void failedToLoadZooKeeperConfigurationMapping(@StackTrace(level = MessageLevel.DEBUG) Exception e);
+
+ @Message(level = MessageLevel.ERROR,
text = "Failed to load service discovery URL definition configuration {0}: {1}")
void failedToLoadServiceDiscoveryURLDefConfiguration(final String configuration,
@StackTrace(level = MessageLevel.ERROR) Exception e);
http://git-wip-us.apache.org/repos/asf/knox/blob/7025086a/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/WebHdfsUrlCreator.java
----------------------------------------------------------------------
diff --git a/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/WebHdfsUrlCreator.java b/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/WebHdfsUrlCreator.java
index 1c65982..9c7d65b 100644
--- a/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/WebHdfsUrlCreator.java
+++ b/gateway-discovery-ambari/src/main/java/org/apache/knox/gateway/topology/discovery/ambari/WebHdfsUrlCreator.java
@@ -43,30 +43,31 @@ public class WebHdfsUrlCreator implements ServiceURLCreator {
if (SERVICE.equals(service)) {
AmbariCluster.ServiceConfiguration sc = cluster.getServiceConfiguration("HDFS", "hdfs-site");
+ if (sc != null) {
+ // First, check if it's HA config
+ String nameServices = null;
+ AmbariComponent nameNodeComp = cluster.getComponent("NAMENODE");
+ if (nameNodeComp != null) {
+ nameServices = nameNodeComp.getConfigProperty("dfs.nameservices");
+ }
- // First, check if it's HA config
- String nameServices = null;
- AmbariComponent nameNodeComp = cluster.getComponent("NAMENODE");
- if (nameNodeComp != null) {
- nameServices = nameNodeComp.getConfigProperty("dfs.nameservices");
- }
-
- if (nameServices != null && !nameServices.isEmpty()) {
- // If it is an HA configuration
- Map<String, String> props = sc.getProperties();
-
- // Name node HTTP addresses are defined as properties of the form:
- // dfs.namenode.http-address.<NAMESERVICES>.nn<INDEX>
- // So, this iterates over the nn<INDEX> properties until there is no such property (since it cannot be known how
- // many are defined by any other means).
- int i = 1;
- String propertyValue = getHANameNodeHttpAddress(props, nameServices, i++);
- while (propertyValue != null) {
- urls.add(createURL(propertyValue));
- propertyValue = getHANameNodeHttpAddress(props, nameServices, i++);
+ if (nameServices != null && !nameServices.isEmpty()) {
+ // If it is an HA configuration
+ Map<String, String> props = sc.getProperties();
+
+ // Name node HTTP addresses are defined as properties of the form:
+ // dfs.namenode.http-address.<NAMESERVICES>.nn<INDEX>
+ // So, this iterates over the nn<INDEX> properties until there is no such property (since it cannot be known how
+ // many are defined by any other means).
+ int i = 1;
+ String propertyValue = getHANameNodeHttpAddress(props, nameServices, i++);
+ while (propertyValue != null) {
+ urls.add(createURL(propertyValue));
+ propertyValue = getHANameNodeHttpAddress(props, nameServices, i++);
+ }
+ } else { // If it's not an HA configuration, get the single name node HTTP address
+ urls.add(createURL(sc.getProperties().get("dfs.namenode.http-address")));
}
- } else { // If it's not an HA configuration, get the single name node HTTP address
- urls.add(createURL(sc.getProperties().get("dfs.namenode.http-address")));
}
}
http://git-wip-us.apache.org/repos/asf/knox/blob/7025086a/gateway-discovery-ambari/src/main/resources/ambari-service-discovery-zk-config-mapping.properties
----------------------------------------------------------------------
diff --git a/gateway-discovery-ambari/src/main/resources/ambari-service-discovery-zk-config-mapping.properties b/gateway-discovery-ambari/src/main/resources/ambari-service-discovery-zk-config-mapping.properties
new file mode 100644
index 0000000..2f5e4ba
--- /dev/null
+++ b/gateway-discovery-ambari/src/main/resources/ambari-service-discovery-zk-config-mapping.properties
@@ -0,0 +1,50 @@
+##########################################################################
+# 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.
+##########################################################################
+
+# HIVE
+HIVE.config=HIVE:hive-site
+HIVE.enabled=hive.server2.support.dynamic.service.discovery
+HIVE.ensemble=hive.zookeeper.quorum
+HIVE.namespace=hive.server2.zookeeper.namespace
+
+# HBASE
+WEBHBASE.config=HBASE:hbase-site
+WEBHBASE.ensemble=hbase.zookeeper.quorum
+WEBHBASE.namespace=zookeeper.znode.parent
+
+# KAFKA
+KAFKA.config=KAFKA:kafka-broker
+KAFKA.ensemble=zookeeper.connect
+
+# WEBHDFS
+WEBHDFS.config=HDFS:hdfs-site
+WEBHDFS.ensemble=ha.zookeeper.quorum
+
+# OOZIE
+OOZIE.config=OOZIE:oozie-site
+OOZIE.ensemble=oozie.zookeeper.connection.string
+OOZIE.namespace=oozie.zookeeper.namespace
+
+# YARN
+YARN.config=YARN:yarn-site
+YARN.enabled=yarn.resourcemanager.ha.enabled
+YARN.ensemble=yarn.resourcemanager.zk-address
+
+# WEBHCAT
+WEBHCAT.config=WEBHCAT:webhcat-site
+WEBHCAT.ensemble=templeton.zookeeper.hosts
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/knox/blob/7025086a/gateway-discovery-ambari/src/test/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariClusterTest.java
----------------------------------------------------------------------
diff --git a/gateway-discovery-ambari/src/test/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariClusterTest.java b/gateway-discovery-ambari/src/test/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariClusterTest.java
new file mode 100644
index 0000000..260051b
--- /dev/null
+++ b/gateway-discovery-ambari/src/test/java/org/apache/knox/gateway/topology/discovery/ambari/AmbariClusterTest.java
@@ -0,0 +1,150 @@
+/**
+ * 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.knox.gateway.topology.discovery.ambari;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.knox.gateway.topology.discovery.ServiceDiscovery;
+import org.apache.knox.test.TestUtils;
+import org.easymock.EasyMock;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+public class AmbariClusterTest {
+
+ @Test
+ public void testHiveZooKeeperConfiguration() throws Exception {
+
+ final boolean isEnabled = true;
+ final String ensemble = "host1:2181,host2:2181,host3:2181";
+ final String namespace = "hiveserver2";
+
+ Map<String, String> serviceConfigProps = new HashMap<>();
+ serviceConfigProps.put("hive.server2.support.dynamic.service.discovery", String.valueOf(isEnabled));
+ serviceConfigProps.put("hive.zookeeper.quorum", ensemble);
+ serviceConfigProps.put("hive.server2.zookeeper.namespace", namespace);
+
+ AmbariCluster.ZooKeeperConfig config = getZooKeeperConfiguration("HIVE", "hive-site", serviceConfigProps);
+ assertNotNull(config);
+ assertEquals(isEnabled, config.isEnabled());
+ assertEquals(ensemble, config.getEnsemble());
+ assertEquals(namespace, config.getNamespace());
+ }
+
+ @Test
+ public void testWebHBaseZooKeeperConfiguration() throws Exception {
+
+ final boolean isEnabled = true;
+ final String ensemble = "host1:2181,host2:2181,host3:2181";
+ final String namespace = "hbase";
+
+ Map<String, String> serviceConfigProps = new HashMap<>();
+ serviceConfigProps.put("hbase.zookeeper.quorum", ensemble);
+ serviceConfigProps.put("zookeeper.znode.parent", namespace);
+
+ AmbariCluster.ZooKeeperConfig config = getZooKeeperConfiguration("WEBHBASE", "HBASE", "hbase-site", serviceConfigProps);
+ assertNotNull(config);
+ assertEquals(isEnabled, config.isEnabled());
+ assertEquals(ensemble, config.getEnsemble());
+ assertEquals(namespace, config.getNamespace());
+ }
+
+
+ @Test
+ public void testKafkaZooKeeperConfiguration() throws Exception {
+
+ final boolean isEnabled = true;
+ final String ensemble = "host1:2181,host2:2181,host3:2181";
+
+ Map<String, String> serviceConfigProps = new HashMap<>();
+ serviceConfigProps.put("zookeeper.connect", ensemble);
+
+ AmbariCluster.ZooKeeperConfig config = getZooKeeperConfiguration("KAFKA", "kafka-broker", serviceConfigProps);
+ assertNotNull(config);
+ assertEquals(isEnabled, config.isEnabled());
+ assertEquals(ensemble, config.getEnsemble());
+ assertNull(config.getNamespace());
+ }
+
+ @Test
+ public void testWebHDFSZooKeeperConfiguration() throws Exception {
+
+ final boolean isEnabled = true;
+ final String ensemble = "host3:2181,host2:2181,host1:2181";
+
+ Map<String, String> serviceConfigProps = new HashMap<>();
+ serviceConfigProps.put("ha.zookeeper.quorum", ensemble);
+
+ AmbariCluster.ZooKeeperConfig config = getZooKeeperConfiguration("WEBHDFS", "HDFS", "hdfs-site", serviceConfigProps);
+ assertNotNull(config);
+ assertEquals(isEnabled, config.isEnabled());
+ assertEquals(ensemble, config.getEnsemble());
+ assertNull(config.getNamespace());
+ }
+
+
+ @Test
+ public void testOozieZooKeeperConfiguration() throws Exception {
+
+ final boolean isEnabled = true;
+ final String ensemble = "host1:2181,host2:2181,host3:2181";
+ final String namespace = "hiveserver2";
+
+ Map<String, String> serviceConfigProps = new HashMap<>();
+ serviceConfigProps.put("oozie.zookeeper.connection.string", ensemble);
+ serviceConfigProps.put("oozie.zookeeper.namespace", namespace);
+
+ AmbariCluster.ZooKeeperConfig config = getZooKeeperConfiguration("OOZIE", "oozie-site", serviceConfigProps);
+ assertNotNull(config);
+ assertEquals(isEnabled, config.isEnabled());
+ assertEquals(ensemble, config.getEnsemble());
+ assertEquals(namespace, config.getNamespace());
+ }
+
+
+ private ServiceDiscovery.Cluster.ZooKeeperConfig getZooKeeperConfiguration(final String serviceName,
+ final String configType,
+ final Map<String, String> serviceConfigProps) {
+ return getZooKeeperConfiguration(serviceName, serviceName, configType, serviceConfigProps);
+ }
+
+
+ private ServiceDiscovery.Cluster.ZooKeeperConfig getZooKeeperConfiguration(final String serviceName,
+ final String componentName,
+ final String configType,
+ final Map<String, String> serviceConfigProps) {
+
+ AmbariCluster.ServiceConfiguration sc = EasyMock.createNiceMock(AmbariCluster.ServiceConfiguration.class);
+ EasyMock.expect(sc.getProperties()).andReturn(serviceConfigProps).anyTimes();
+ EasyMock.replay(sc);
+
+ AmbariCluster cluster = new AmbariCluster("test");
+ cluster.addServiceConfiguration(componentName, configType, sc);
+
+ return cluster.getZooKeeperConfiguration(serviceName);
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/7025086a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/deploy/HaProviderDeploymentContributor.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/deploy/HaProviderDeploymentContributor.java b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/deploy/HaProviderDeploymentContributor.java
index 2f3664f..00c2562 100644
--- a/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/deploy/HaProviderDeploymentContributor.java
+++ b/gateway-provider-ha/src/main/java/org/apache/knox/gateway/ha/deploy/HaProviderDeploymentContributor.java
@@ -26,10 +26,12 @@ import org.apache.knox.gateway.ha.provider.HaServiceConfig;
import org.apache.knox.gateway.ha.provider.HaServletContextListener;
import org.apache.knox.gateway.ha.provider.impl.HaDescriptorFactory;
import org.apache.knox.gateway.ha.provider.impl.HaDescriptorManager;
+import org.apache.knox.gateway.ha.provider.impl.HaServiceConfigConstants;
import org.apache.knox.gateway.ha.provider.impl.i18n.HaMessages;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
import org.apache.knox.gateway.topology.Provider;
import org.apache.knox.gateway.topology.Service;
+import org.apache.knox.gateway.topology.Topology;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import java.io.IOException;
@@ -60,10 +62,29 @@ public class HaProviderDeploymentContributor extends ProviderDeploymentContribut
@Override
public void contributeProvider(DeploymentContext context, Provider provider) {
+ Topology topology = context.getTopology();
Map<String, String> params = provider.getParams();
HaDescriptor descriptor = HaDescriptorFactory.createDescriptor();
for (Entry<String, String> entry : params.entrySet()) {
- HaServiceConfig config = HaDescriptorFactory.createServiceConfig(entry.getKey(), entry.getValue());
+ String role = entry.getKey();
+ String roleParams = entry.getValue();
+
+ // Create the config based on whatever is specified at the provider level
+ HaServiceConfig config = HaDescriptorFactory.createServiceConfig(role, roleParams);
+
+ // Check for service-level param overrides
+ Map<String, String> serviceLevelParams = null;
+ for (Service s : topology.getServices()) {
+ if (s.getRole().equals(role)) {
+ serviceLevelParams = s.getParams();
+ break;
+ }
+ }
+
+ // Apply any service-level param overrides
+ applyParamOverrides(config, serviceLevelParams);
+
+ // Add the reconciled HA service config to the descriptor
descriptor.addServiceConfig(config);
}
StringWriter writer = new StringWriter();
@@ -79,6 +100,51 @@ public class HaProviderDeploymentContributor extends ProviderDeploymentContribut
context.addDescriptor(HA_DESCRIPTOR_NAME, descriptor);
}
+ /**
+ * Apply the param values from the specified map to the specified HaServiceConfig.
+ *
+ * @param config An HaServiceConfig
+ * @param serviceLevelParams Service-level param overrides.
+ */
+ private void applyParamOverrides(HaServiceConfig config, Map<String, String> serviceLevelParams) {
+ if (serviceLevelParams != null && !serviceLevelParams.isEmpty()) {
+ String enabled = serviceLevelParams.get(HaServiceConfigConstants.CONFIG_PARAM_ENABLED);
+ if (enabled != null) {
+ config.setEnabled(Boolean.valueOf(enabled));
+ }
+
+ String failOverSleep = serviceLevelParams.get(HaServiceConfigConstants.CONFIG_PARAM_FAILOVER_SLEEP);
+ if (failOverSleep != null) {
+ config.setFailoverSleep(Integer.valueOf(failOverSleep));
+ }
+
+ String failOverAttempts = serviceLevelParams.get(HaServiceConfigConstants.CONFIG_PARAM_MAX_FAILOVER_ATTEMPTS);
+ if (failOverAttempts != null) {
+ config.setMaxFailoverAttempts(Integer.valueOf(failOverAttempts));
+ }
+
+ String retrySleep = serviceLevelParams.get(HaServiceConfigConstants.CONFIG_PARAM_RETRY_SLEEP);
+ if (retrySleep != null) {
+ config.setRetrySleep(Integer.valueOf(retrySleep));
+ }
+
+ String retryAttempts = serviceLevelParams.get(HaServiceConfigConstants.CONFIG_PARAM_MAX_RETRY_ATTEMPTS);
+ if (retryAttempts != null) {
+ config.setMaxRetryAttempts(Integer.valueOf(retryAttempts));
+ }
+
+ String zkEnsemble = serviceLevelParams.get(HaServiceConfigConstants.CONFIG_PARAM_ZOOKEEPER_ENSEMBLE);
+ if (zkEnsemble != null) {
+ config.setZookeeperEnsemble(zkEnsemble);
+ }
+
+ String zkNamespace = serviceLevelParams.get(HaServiceConfigConstants.CONFIG_PARAM_ZOOKEEPER_NAMESPACE);
+ if (zkNamespace != null) {
+ config.setZookeeperNamespace(zkNamespace);
+ }
+ }
+ }
+
@Override
public void finalizeContribution(DeploymentContext context) {
if (context.getDescriptor(HA_DESCRIPTOR_NAME) != null) {
http://git-wip-us.apache.org/repos/asf/knox/blob/7025086a/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/deploy/HaProviderDeploymentContributorTest.java
----------------------------------------------------------------------
diff --git a/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/deploy/HaProviderDeploymentContributorTest.java b/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/deploy/HaProviderDeploymentContributorTest.java
index f28baaf..6d3bf1e 100644
--- a/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/deploy/HaProviderDeploymentContributorTest.java
+++ b/gateway-provider-ha/src/test/java/org/apache/knox/gateway/ha/deploy/HaProviderDeploymentContributorTest.java
@@ -17,13 +17,35 @@
*/
package org.apache.knox.gateway.ha.deploy;
+import org.apache.knox.gateway.config.GatewayConfig;
+import org.apache.knox.gateway.deploy.DeploymentContext;
import org.apache.knox.gateway.deploy.ProviderDeploymentContributor;
+import org.apache.knox.gateway.descriptor.FilterParamDescriptor;
+import org.apache.knox.gateway.descriptor.GatewayDescriptor;
+import org.apache.knox.gateway.descriptor.ResourceDescriptor;
+import org.apache.knox.gateway.ha.provider.HaDescriptor;
+import org.apache.knox.gateway.ha.provider.HaServiceConfig;
+import org.apache.knox.gateway.topology.Provider;
+import org.apache.knox.gateway.topology.Service;
+import org.apache.knox.gateway.topology.Topology;
+import org.easymock.EasyMock;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.jboss.shrinkwrap.descriptor.api.webapp30.WebAppDescriptor;
import org.junit.Test;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import java.util.ServiceLoader;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
@@ -43,4 +65,347 @@ public class HaProviderDeploymentContributorTest {
fail( "Failed to find " + HaProviderDeploymentContributor.class.getName() + " via service loader." );
}
+ /**
+ * Basically, a backward-compatibility test to ensure that HaProvider service params specified ONLY at the provider
+ * level still work.
+ */
+ @Test
+ public void testProviderLevelParams() throws Exception {
+ // Define some provider params
+ Map<String, String> providerParams = new HashMap<>();
+
+ // Specify all the possible params at the HaProvider level for TestRoleTwo
+ providerParams.put("TestRoleOne",
+ "enabled=false;" +
+ "maxRetryAttempts=5;"+
+ "retrySleep=50;"+
+ "maxFailoverAttempts=4;"+
+ "failoverSleep=40;"+
+ "zookeeperNamespace=testRoleOne;"+
+ "zookeeperEnsemble=http://host1:2181,http://host2:2181");
+
+ Provider haProvider = createHaProvider(providerParams);
+
+ // Define the topology content (e.g., services)
+ Collection<Service> topologyServices = new HashSet<>();
+
+ // A service with no param overrides
+ Service testRoleOneService = EasyMock.createNiceMock(Service.class);
+ EasyMock.expect(testRoleOneService.getRole()).andReturn("TestRoleOne").anyTimes();
+ EasyMock.expect(testRoleOneService.getName()).andReturn("TestRoleOneService").anyTimes();
+ EasyMock.expect(testRoleOneService.getParams()).andReturn(Collections.emptyMap()).anyTimes();
+ EasyMock.replay(testRoleOneService);
+ topologyServices.add(testRoleOneService);
+
+ Topology topology = EasyMock.createNiceMock(Topology.class);
+ EasyMock.expect(topology.getServices()).andReturn(topologyServices).anyTimes();
+ EasyMock.replay(topology);
+
+ WebArchive war = EasyMock.createNiceMock(WebArchive.class);
+ EasyMock.replay(war);
+
+ DeploymentContext context = new DescriptorCaptureDeploymentContext(topology, war);
+
+ // Invoke the contributor
+ HaProviderDeploymentContributor haPDC = new HaProviderDeploymentContributor();
+ haPDC.contributeProvider(context, haProvider);
+
+ HaDescriptor descriptor = context.getDescriptor("ha.provider.descriptor");
+ assertNotNull(descriptor);
+ assertEquals(1, descriptor.getServiceConfigs().size());
+
+ validateServiceHaConfig(descriptor.getServiceConfig("TestRoleOne"),
+ false, 40, 4, 50, 5, "testRoleOne", "http://host1:2181,http://host2:2181");
+ }
+
+ /**
+ * Simple test verifying that HaProvider service params specified ONLY at the service level works.
+ */
+ @Test
+ public void testServiceLevelParamOverrides_NoProviderParams() throws Exception {
+ // Define some provider params
+ Map<String, String> providerParams = new HashMap<>();
+
+ // Specify all the possible params at the HaProvider level for TestRoleTwo
+ providerParams.put("TestRoleOne","");
+
+ Provider haProvider = createHaProvider(providerParams);
+
+ // Define the topology content (e.g., services)
+ Collection<Service> topologyServices = new HashSet<>();
+
+ // Specify all the possible params in the TestRoleOne service level
+ Map<String, String> testRoleOneParams = new HashMap<>();
+ testRoleOneParams.put("enabled", "true");
+ testRoleOneParams.put("maxRetryAttempts", "6");
+ testRoleOneParams.put("retrySleep", "60");
+ testRoleOneParams.put("maxFailoverAttempts", "8");
+ testRoleOneParams.put("failoverSleep", "80");
+ testRoleOneParams.put("zookeeperNamespace", "testRoleOneOverride");
+ testRoleOneParams.put("zookeeperEnsemble", "http://host3:2181,http://host4:2181");
+
+ // A service with all the params overriden
+ Service testRoleOneService = EasyMock.createNiceMock(Service.class);
+ EasyMock.expect(testRoleOneService.getRole()).andReturn("TestRoleOne").anyTimes();
+ EasyMock.expect(testRoleOneService.getName()).andReturn("TestRoleOneService").anyTimes();
+ EasyMock.expect(testRoleOneService.getParams()).andReturn(testRoleOneParams).anyTimes();
+ EasyMock.replay(testRoleOneService);
+ topologyServices.add(testRoleOneService);
+
+ Topology topology = EasyMock.createNiceMock(Topology.class);
+ EasyMock.expect(topology.getServices()).andReturn(topologyServices).anyTimes();
+ EasyMock.replay(topology);
+
+ WebArchive war = EasyMock.createNiceMock(WebArchive.class);
+ EasyMock.replay(war);
+
+ DeploymentContext context = new DescriptorCaptureDeploymentContext(topology, war);
+
+ // Invoke the contributor
+ HaProviderDeploymentContributor haPDC = new HaProviderDeploymentContributor();
+ haPDC.contributeProvider(context, haProvider);
+
+ HaDescriptor descriptor = context.getDescriptor("ha.provider.descriptor");
+ assertNotNull(descriptor);
+ assertEquals(1, descriptor.getServiceConfigs().size());
+
+ validateServiceHaConfig(descriptor.getServiceConfig("TestRoleOne"),
+ true, 80, 8, 60, 6, "testRoleOneOverride", "http://host3:2181,http://host4:2181");
+ }
+
+ /**
+ * Verify a mixture of provider-level params and service-level params.
+ */
+ @Test
+ public void testServiceLevelParamOverrides_SubsetProviderParams() throws Exception {
+ // Define some provider params
+ Map<String, String> providerParams = new HashMap<>();
+
+ // Specify all the possible params at the HaProvider level for TestRoleTwo
+ providerParams.put("TestRoleOne",
+ "enabled=false;" +
+ "maxRetryAttempts=5;"+
+ "maxFailoverAttempts=4;"+
+ "failoverSleep=40");
+
+ Provider haProvider = createHaProvider(providerParams);
+
+ // Define the topology content (e.g., services)
+ Collection<Service> topologyServices = new HashSet<>();
+
+ // Specify all the possible params in the TestRoleOne service level
+ Map<String, String> testRoleOneParams = new HashMap<>();
+ testRoleOneParams.put("enabled", "true");
+ testRoleOneParams.put("retrySleep", "60");
+ testRoleOneParams.put("zookeeperNamespace", "testRoleOneOverride");
+ testRoleOneParams.put("zookeeperEnsemble", "http://host3:2181,http://host4:2181");
+
+ // A service with all the params overriden
+ Service testRoleOneService = EasyMock.createNiceMock(Service.class);
+ EasyMock.expect(testRoleOneService.getRole()).andReturn("TestRoleOne").anyTimes();
+ EasyMock.expect(testRoleOneService.getName()).andReturn("TestRoleOneService").anyTimes();
+ EasyMock.expect(testRoleOneService.getParams()).andReturn(testRoleOneParams).anyTimes();
+ EasyMock.replay(testRoleOneService);
+ topologyServices.add(testRoleOneService);
+
+ Topology topology = EasyMock.createNiceMock(Topology.class);
+ EasyMock.expect(topology.getServices()).andReturn(topologyServices).anyTimes();
+ EasyMock.replay(topology);
+
+ WebArchive war = EasyMock.createNiceMock(WebArchive.class);
+ EasyMock.replay(war);
+
+ DeploymentContext context = new DescriptorCaptureDeploymentContext(topology, war);
+
+ // Invoke the contributor
+ HaProviderDeploymentContributor haPDC = new HaProviderDeploymentContributor();
+ haPDC.contributeProvider(context, haProvider);
+
+ HaDescriptor descriptor = context.getDescriptor("ha.provider.descriptor");
+ assertNotNull(descriptor);
+ assertEquals(1, descriptor.getServiceConfigs().size());
+
+ validateServiceHaConfig(descriptor.getServiceConfig("TestRoleOne"),
+ true, 40, 4, 60, 5, "testRoleOneOverride", "http://host3:2181,http://host4:2181");
+ }
+
+
+ @Test
+ public void testServiceLevelParamOverrides_MultipleMixed() throws Exception {
+
+ // Define some provider params
+ Map<String, String> providerParams = new HashMap<>();
+
+ // Specify a subset of the possible HaProvider-level params for TestRoleOne
+ providerParams.put("TestRoleOne",
+ "enabled=true;maxRetryAttempts=1;retrySleep=10;maxFailoverAttempts=2;failoverSleep=20");
+
+ // Specify all the possible params at the HaProvider level for TestRoleTwo
+ providerParams.put("TestRoleTwo",
+ "enabled=false;" +
+ "maxRetryAttempts=3;"+
+ "retrySleep=30;"+
+ "maxFailoverAttempts=4;"+
+ "failoverSleep=40;"+
+ "zookeeperNamespace=testRoleTwo;"+
+ "zookeeperEnsemble=http://host1:2181,http://host2:2181");
+
+ Provider testHaProvider = createHaProvider(providerParams);
+
+ // Define the topology content (e.g., services)
+ Collection<Service> topologyServices = new HashSet<>();
+
+ // A service with no param overrides
+ Service testRoleOneService = EasyMock.createNiceMock(Service.class);
+ EasyMock.expect(testRoleOneService.getRole()).andReturn("TestRoleOne").anyTimes();
+ EasyMock.expect(testRoleOneService.getName()).andReturn("TestRoleOneService").anyTimes();
+ EasyMock.expect(testRoleOneService.getParams()).andReturn(Collections.emptyMap()).anyTimes();
+ EasyMock.replay(testRoleOneService);
+ topologyServices.add(testRoleOneService);
+
+ // Override all the possible params in the TestRoleTwo service level
+ Map<String, String> testRoleTwoParams = new HashMap<>();
+ testRoleTwoParams.put("enabled", "true");
+ testRoleTwoParams.put("maxRetryAttempts", "6");
+ testRoleTwoParams.put("retrySleep", "60");
+ testRoleTwoParams.put("maxFailoverAttempts", "8");
+ testRoleTwoParams.put("failoverSleep", "80");
+ testRoleTwoParams.put("zookeeperNamespace", "testRoleTwoOverride");
+ testRoleTwoParams.put("zookeeperEnsemble", "http://host3:2181,http://host4:2181");
+
+ Service testRoleTwoService = EasyMock.createNiceMock(Service.class);
+ EasyMock.expect(testRoleTwoService.getRole()).andReturn("TestRoleTwo").anyTimes();
+ EasyMock.expect(testRoleTwoService.getName()).andReturn("TestRoleTwoService").anyTimes();
+ EasyMock.expect(testRoleTwoService.getParams()).andReturn(testRoleTwoParams).anyTimes();
+ EasyMock.replay(testRoleTwoService);
+ topologyServices.add(testRoleTwoService);
+
+ Topology topology = EasyMock.createNiceMock(Topology.class);
+ EasyMock.expect(topology.getServices()).andReturn(topologyServices).anyTimes();
+ EasyMock.replay(topology);
+
+ WebArchive war = EasyMock.createNiceMock(WebArchive.class);
+ EasyMock.replay(war);
+
+ DeploymentContext context = new DescriptorCaptureDeploymentContext(topology, war);
+
+ // Invoke the contributor
+ HaProviderDeploymentContributor haPDC = new HaProviderDeploymentContributor();
+ haPDC.contributeProvider(context, testHaProvider);
+
+ HaDescriptor descriptor = context.getDescriptor("ha.provider.descriptor");
+ assertNotNull(descriptor);
+ assertEquals(2, descriptor.getServiceConfigs().size());
+
+ // Validate the service with no-overrides, checking that the provider-level defaults are applied
+ validateServiceHaConfig(descriptor.getServiceConfig("TestRoleOne"),
+ true, 20, 2, 10, 1, null, null);
+
+ // Validate the service with all-overrides, checking that the service-level defaults are applied
+ validateServiceHaConfig(descriptor.getServiceConfig("TestRoleTwo"),
+ true, 80, 8, 60, 6, "testRoleTwoOverride", "http://host3:2181,http://host4:2181");
+ }
+
+
+ /**
+ *
+ * @param config The HaServiceConfig to validate
+ * @param isEnabled The expected enabled param value
+ * @param failoverSleep The expected failoverSleep param value
+ * @param maxFailoverAttempts The expected maxFailoverAttempts param value
+ * @param retrySleep The expected retrySleep param value
+ * @param maxRetryAttempts The expected maxRetryAttempts param value
+ * @param zookeeperNamespace The expected zookeeperNamespace param value
+ * @param zookeeperEnsemble The expected zookeeperEnsemble param value
+ */
+ private static void validateServiceHaConfig(HaServiceConfig config,
+ boolean isEnabled,
+ int failoverSleep,
+ int maxFailoverAttempts,
+ int retrySleep,
+ int maxRetryAttempts,
+ String zookeeperNamespace,
+ String zookeeperEnsemble) throws Exception {
+ assertNotNull(config);
+ assertEquals(isEnabled, config.isEnabled());
+ assertEquals(failoverSleep, config.getFailoverSleep());
+ assertEquals(maxFailoverAttempts, config.getMaxFailoverAttempts());
+ assertEquals(retrySleep, config.getRetrySleep());
+ assertEquals(maxRetryAttempts, config.getMaxRetryAttempts());
+
+ if (zookeeperNamespace == null) {
+ assertNull(config.getZookeeperNamespace());
+ } else {
+ assertEquals(zookeeperNamespace, config.getZookeeperNamespace());
+ }
+
+ if (zookeeperEnsemble== null) {
+ assertNull(config.getZookeeperEnsemble());
+ } else {
+ assertEquals(zookeeperEnsemble, config.getZookeeperEnsemble());
+ }
+ }
+
+ private static Provider createHaProvider(Map<String, String> params) {
+ Provider provider = EasyMock.createNiceMock(Provider.class);
+ EasyMock.expect(provider.getRole()).andReturn("ha").anyTimes();
+ EasyMock.expect(provider.getName()).andReturn("HaProvider").anyTimes();
+ EasyMock.expect(provider.getParams()).andReturn(params).anyTimes();
+ EasyMock.replay(provider);
+ return provider;
+ }
+
+
+ private static class DescriptorCaptureDeploymentContext implements DeploymentContext {
+
+ private Topology topology;
+ private WebArchive war;
+ private Map<String, Object> descriptors = new HashMap<>();
+
+ DescriptorCaptureDeploymentContext(Topology topology, WebArchive war) {
+ this.topology = topology;
+ this.war = war;
+ }
+
+ @Override
+ public GatewayConfig getGatewayConfig() {
+ return null;
+ }
+
+ @Override
+ public Topology getTopology() {
+ return topology;
+ }
+
+ @Override
+ public WebArchive getWebArchive() {
+ return war;
+ }
+
+ @Override
+ public WebAppDescriptor getWebAppDescriptor() {
+ return null;
+ }
+
+ @Override
+ public GatewayDescriptor getGatewayDescriptor() {
+ return null;
+ }
+
+ @Override
+ public void contributeFilter(Service service, ResourceDescriptor resource, String role, String name, List<FilterParamDescriptor> params) {
+
+ }
+
+ @Override
+ public void addDescriptor(String name, Object descriptor) {
+ descriptors.put(name, descriptor);
+ }
+
+ @Override
+ public <T> T getDescriptor(String name) {
+ return (T)descriptors.get(name);
+ }
+
+ }
}
http://git-wip-us.apache.org/repos/asf/knox/blob/7025086a/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultTopologyService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultTopologyService.java b/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultTopologyService.java
index 543d294..9c19cc8 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultTopologyService.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/services/topology/impl/DefaultTopologyService.java
@@ -52,6 +52,7 @@ import org.apache.knox.gateway.topology.builder.TopologyBuilder;
import org.apache.knox.gateway.topology.discovery.ClusterConfigurationMonitor;
import org.apache.knox.gateway.topology.monitor.RemoteConfigurationMonitor;
import org.apache.knox.gateway.topology.monitor.RemoteConfigurationMonitorFactory;
+import org.apache.knox.gateway.topology.simple.ProviderConfigurationParser;
import org.apache.knox.gateway.topology.simple.SimpleDescriptor;
import org.apache.knox.gateway.topology.simple.SimpleDescriptorFactory;
import org.apache.knox.gateway.topology.simple.SimpleDescriptorHandler;
@@ -775,10 +776,12 @@ public class DefaultTopologyService
try {
// When a simple descriptor has been created or modified, generate the new topology descriptor
Map<String, File> result = SimpleDescriptorHandler.handle(file, topologiesDir, aliasService);
- log.generatedTopologyForDescriptorChange(result.get("topology").getName(), file.getName());
+ log.generatedTopologyForDescriptorChange(result.get(SimpleDescriptorHandler.RESULT_TOPOLOGY).getName(),
+ file.getName());
// Add the provider config reference relationship for handling updates to the provider config
- String providerConfig = FilenameUtils.normalize(result.get("reference").getAbsolutePath());
+ String providerConfig =
+ FilenameUtils.normalize(result.get(SimpleDescriptorHandler.RESULT_REFERENCE).getAbsolutePath());
if (!providerConfigReferences.containsKey(providerConfig)) {
providerConfigReferences.put(providerConfig, new ArrayList<String>());
}
@@ -817,13 +820,9 @@ public class DefaultTopologyService
/**
* Change handler for shared provider configurations
*/
- public static class SharedProviderConfigMonitor extends FileAlterationListenerAdaptor
- implements FileFilter {
+ public static class SharedProviderConfigMonitor extends FileAlterationListenerAdaptor implements FileFilter {
- static final List<String> SUPPORTED_EXTENSIONS = new ArrayList<>();
- static {
- SUPPORTED_EXTENSIONS.add("xml");
- }
+ static final List<String> SUPPORTED_EXTENSIONS = ProviderConfigurationParser.SUPPORTED_EXTENSIONS;
private DescriptorsMonitor descriptorsMonitor;
private File descriptorsDir;
http://git-wip-us.apache.org/repos/asf/knox/blob/7025086a/gateway-server/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/ProviderConfiguration.java b/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/ProviderConfiguration.java
new file mode 100644
index 0000000..405a8de
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/ProviderConfiguration.java
@@ -0,0 +1,39 @@
+/**
+ * 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.knox.gateway.topology.simple;
+
+
+import java.util.List;
+import java.util.Map;
+
+public interface ProviderConfiguration {
+
+ List<Provider> getProviders();
+
+
+ interface Provider {
+
+ String getRole();
+
+ String getName();
+
+ boolean isEnabled();
+
+ Map<String, String> getParams();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/7025086a/gateway-server/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/ProviderConfigurationParser.java b/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/ProviderConfigurationParser.java
new file mode 100644
index 0000000..4bfc456
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/ProviderConfigurationParser.java
@@ -0,0 +1,260 @@
+/**
+ * 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.knox.gateway.topology.simple;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import org.apache.commons.io.FilenameUtils;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ProviderConfigurationParser {
+
+ private static final String EXT_XML = "xml";
+ private static final String EXT_JSON = "json";
+ private static final String EXT_YML = "yml";
+ private static final String EXT_YAML = "yaml";
+
+ public static final List<String> SUPPORTED_EXTENSIONS = Arrays.asList(EXT_XML, EXT_JSON, EXT_YML, EXT_YAML);
+
+
+ public static ProviderConfiguration parse(String path) throws Exception {
+ return parse(new File(path));
+ }
+
+ public static ProviderConfiguration parse(File file) throws Exception {
+ ProviderConfiguration providerConfig = null;
+
+ String extension = FilenameUtils.getExtension(file.getName());
+ if (SUPPORTED_EXTENSIONS.contains(extension)) {
+
+ if (isXML(extension)) {
+ providerConfig = parseXML(file);
+ } else if (isJSON(extension)) {
+ providerConfig = parseJSON(file);
+ } else if (isYAML(extension)) {
+ providerConfig = parseYAML(file);
+ }
+ } else {
+ throw new IllegalArgumentException("Unsupported provider configuration format: " + extension);
+ }
+
+ return providerConfig;
+ }
+
+ private static boolean isXML(String extension) {
+ return EXT_XML.equals(extension);
+ }
+
+ private static boolean isJSON(String extension) {
+ return EXT_JSON.equals(extension);
+ }
+
+ private static boolean isYAML(String extension) {
+ return EXT_YAML.equals(extension) || EXT_YML.equals(extension);
+ }
+
+
+ static ProviderConfiguration parseXML(File file) throws Exception {
+ return parseXML(new FileInputStream(file));
+ }
+
+
+ static ProviderConfiguration parseXML(InputStream in) throws Exception {
+ XMLProviderConfiguration providerConfig = null;
+
+ JAXBContext jaxbContext = JAXBContext.newInstance(XMLProviderConfiguration.class);
+ Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
+ providerConfig = (XMLProviderConfiguration) jaxbUnmarshaller.unmarshal(in);
+
+ return providerConfig;
+ }
+
+
+ static ProviderConfiguration parseJSON(File file) throws IOException {
+ return parseJSON(new FileInputStream(file));
+ }
+
+
+ static ProviderConfiguration parseJSON(InputStream in) throws IOException {
+ final ObjectMapper mapper = new ObjectMapper();
+ JSONProviderConfiguration providerConfig = mapper.readValue(in, JSONProviderConfiguration.class);
+ return providerConfig;
+ }
+
+
+ static ProviderConfiguration parseYAML(File file) throws IOException {
+ return parseYAML(new FileInputStream(file));
+ }
+
+ static ProviderConfiguration parseYAML(InputStream in) throws IOException {
+ final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
+ JSONProviderConfiguration providerConfig = mapper.readValue(in, JSONProviderConfiguration.class);
+ return providerConfig;
+ }
+
+
+ // XML Provider Configuration Model
+ @XmlRootElement(name="gateway")
+ private static class XMLProviderConfiguration implements ProviderConfiguration {
+
+ @XmlElement(name="provider")
+ private List<XMLProvider> providers;
+
+ @Override
+ public List<Provider> getProviders() {
+ List<Provider> plist = new ArrayList<>();
+ if (providers != null) {
+ plist.addAll(providers);
+ }
+ return plist;
+ }
+
+ @XmlAccessorType(XmlAccessType.NONE)
+ private static class XMLProvider implements ProviderConfiguration.Provider {
+ @XmlElement
+ private String role;
+
+ @XmlElement
+ private String name;
+
+ @XmlElement
+ private boolean enabled;
+
+ @XmlElement(name = "param")
+ private List<XMLParam> params;
+
+ @Override
+ public String getRole() {
+ return role;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ @Override
+ public Map<String, String> getParams() {
+ Map<String, String> result = new HashMap<>();
+ if (params != null) {
+ for (XMLParam p : params) {
+ result.put(p.name, p.value);
+ }
+ }
+ return result;
+ }
+
+ @XmlAccessorType(XmlAccessType.NONE)
+ private static class XMLParam {
+ @XmlElement
+ private String name;
+
+ @XmlElement
+ private String value;
+
+ String getName() {
+ return name;
+ }
+
+ String getValue() {
+ return value;
+ }
+ }
+ }
+
+ }
+
+
+ // JSON/YAML Provider Configuration Model
+ private static class JSONProviderConfiguration implements ProviderConfiguration {
+
+ @JsonProperty("providers")
+ private List<JSONProvider> providers;
+
+ @Override
+ public List<Provider> getProviders() {
+ List<Provider> plist = new ArrayList<>();
+ if (providers != null) {
+ plist.addAll(providers);
+ }
+ return plist;
+ }
+
+ private static class JSONProvider implements ProviderConfiguration.Provider {
+
+ @JsonProperty("role")
+ private String role;
+
+ @JsonProperty("name")
+ private String name;
+
+ @JsonProperty("enabled")
+ private boolean enabled;
+
+ @JsonProperty("params")
+ private Map<String, String> params;
+
+ @Override
+ public String getRole() {
+ return role;
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ @Override
+ public Map<String, String> getParams() {
+ Map<String, String> result = new HashMap<>();
+ if (params != null) {
+ result.putAll(params);
+ }
+ return result;
+ }
+ }
+
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/7025086a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java b/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java
index 30786dc..55411d8 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorHandler.java
@@ -18,11 +18,10 @@ package org.apache.knox.gateway.topology.simple;
import java.io.BufferedWriter;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileWriter;
-import java.io.InputStreamReader;
import java.io.IOException;
+import java.io.StringWriter;
import java.net.URI;
import java.net.URISyntaxException;
@@ -31,6 +30,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import org.apache.knox.gateway.GatewayServer;
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
@@ -50,6 +50,28 @@ import org.apache.knox.gateway.topology.discovery.ServiceDiscoveryFactory;
*/
public class SimpleDescriptorHandler {
+ /**
+ * The name of the property in the result Map for the topology file.
+ */
+ public static final String RESULT_TOPOLOGY = "topology";
+
+ /**
+ * The name of the property in the result Map for the provider configuration file applied to the generated topology.
+ */
+ public static final String RESULT_REFERENCE = "reference";
+
+ private static final String DEFAULT_DISCOVERY_TYPE = "AMBARI";
+
+ private static final String[] PROVIDER_CONFIG_FILE_EXTENSIONS;
+ static {
+
+ PROVIDER_CONFIG_FILE_EXTENSIONS = new String[ProviderConfigurationParser.SUPPORTED_EXTENSIONS.size()];
+ int i = 0;
+ for (String ext : ProviderConfigurationParser.SUPPORTED_EXTENSIONS) {
+ PROVIDER_CONFIG_FILE_EXTENSIONS[i++] = "." + ext;
+ }
+ }
+
private static final Service[] NO_GATEWAY_SERVICES = new Service[]{};
private static final SimpleDescriptorMessages log = MessagesFactory.get(SimpleDescriptorMessages.class);
@@ -77,33 +99,13 @@ public class SimpleDescriptorHandler {
}
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());
-
- // Use the discovery type from the descriptor. If it's unspecified, employ the default type.
- String discoveryType = desc.getDiscoveryType();
- if (discoveryType == null) {
- discoveryType = "AMBARI";
- }
- // Use the cached discovery object for the required type, if it has already been loaded
- ServiceDiscovery sd = discoveryInstances.get(discoveryType);
- if (sd == null) {
- sd = ServiceDiscoveryFactory.get(discoveryType, gatewayServices);
- discoveryInstances.put(discoveryType, sd);
- }
- ServiceDiscovery.Cluster cluster = sd.discover(sdc, desc.getClusterName());
-
- List<String> validServiceNames = new ArrayList<>();
-
- Map<String, Map<String, String>> serviceParams = new HashMap<>();
- Map<String, List<String>> serviceURLs = new HashMap<>();
+ List<String> validServiceNames = new ArrayList<>();
+ Map<String, Map<String, String>> serviceParams = new HashMap<>();
+ Map<String, List<String>> serviceURLs = new HashMap<>();
+ // Discover the cluster details required by the descriptor
+ ServiceDiscovery.Cluster cluster = performDiscovery(desc, gatewayServices);
if (cluster != null) {
for (SimpleDescriptor.Service descService : desc.getServices()) {
String serviceName = descService.getName();
@@ -155,133 +157,53 @@ public class SimpleDescriptorHandler {
log.unableCreatePasswordForEncryption(desc.getName());
}
- BufferedWriter fw = null;
- topologyDescriptor = null;
- File providerConfig;
- 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");
-
- fw = new BufferedWriter(new FileWriter(topologyDescriptor));
-
- fw.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
-
- fw.write("<!--==============================================-->\n");
- fw.write("<!-- DO NOT EDIT. This is an auto-generated file. -->\n");
- fw.write("<!--==============================================-->\n");
-
- fw.write("<topology>\n");
-
- // KNOX-1105 Indicate that this topology was auto-generated
- fw.write(" <generated>true</generated>\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();
+ // Generate the topology file
+ return generateTopology(desc, srcDirectory, destDirectory, cluster, validServiceNames, serviceURLs, serviceParams);
+ }
- // Services
- // Sort the service names to write the services alphabetically
- List<String> serviceNames = new ArrayList<>(validServiceNames);
- Collections.sort(serviceNames);
- // Write the service declarations
- for (String serviceName : serviceNames) {
- fw.write("\n");
- fw.write(" <service>\n");
- fw.write(" <role>" + serviceName + "</role>\n");
-
- // URLs
- List<String> urls = serviceURLs.get(serviceName);
- if (urls != null) {
- for (String url : urls) {
- fw.write(" <url>" + url + "</url>\n");
- }
- }
-
- // Params
- Map<String, String> svcParams = serviceParams.get(serviceName);
- if (svcParams != null) {
- for (String paramName : svcParams.keySet()) {
- fw.write(" <param>\n");
- fw.write(" <name>" + paramName + "</name>\n");
- fw.write(" <value>" + svcParams.get(paramName) + "</value>\n");
- fw.write(" </param>\n");
- }
- }
+ private static ServiceDiscovery.Cluster performDiscovery(SimpleDescriptor desc, Service...gatewayServices) {
+ DefaultServiceDiscoveryConfig sdc = new DefaultServiceDiscoveryConfig(desc.getDiscoveryAddress());
+ sdc.setUser(desc.getDiscoveryUser());
+ sdc.setPasswordAlias(desc.getDiscoveryPasswordAlias());
- fw.write(" </service>\n");
- }
+ // Use the discovery type from the descriptor. If it's unspecified, employ the default type.
+ String discoveryType = desc.getDiscoveryType();
+ if (discoveryType == null) {
+ discoveryType = DEFAULT_DISCOVERY_TYPE;
+ }
- // Applications
- List<SimpleDescriptor.Application> apps = desc.getApplications();
- if (apps != null) {
- for (SimpleDescriptor.Application app : apps) {
- fw.write(" <application>\n");
- fw.write(" <name>" + app.getName() + "</name>\n");
+ // Use the cached discovery object for the required type, if it has already been loaded
+ ServiceDiscovery sd = discoveryInstances.get(discoveryType);
+ if (sd == null) {
+ sd = ServiceDiscoveryFactory.get(discoveryType, gatewayServices);
+ discoveryInstances.put(discoveryType, sd);
+ }
- // URLs
- List<String> urls = app.getURLs();
- if (urls != null) {
- for (String url : urls) {
- fw.write(" <url>" + url + "</url>\n");
- }
- }
+ return sd.discover(sdc, desc.getClusterName());
+ }
- // Params
- Map<String, String> appParams = app.getParams();
- if (appParams != null) {
- for (String paramName : appParams.keySet()) {
- fw.write(" <param>\n");
- fw.write(" <name>" + paramName + "</name>\n");
- fw.write(" <value>" + appParams.get(paramName) + "</value>\n");
- fw.write(" </param>\n");
- }
- }
- fw.write(" </application>\n");
- }
- }
+ private static ProviderConfiguration handleProviderConfiguration(SimpleDescriptor desc, File providerConfig) {
+ // Verify that the referenced provider configuration exists before attempting to read it
+ if (providerConfig == null) {
+ log.failedToResolveProviderConfigRef(desc.getProviderConfig());
+ throw new IllegalArgumentException("Unresolved provider configuration reference: " +
+ desc.getProviderConfig() + " ; Topology update aborted!");
+ }
- fw.write("</topology>\n");
+ // Parse the contents of the referenced provider config
+ ProviderConfiguration parsedConfig = null;
- fw.flush();
- } catch (IOException e) {
- log.failedToGenerateTopologyFromSimpleDescriptor(topologyDescriptor.getName(), e);
- topologyDescriptor.delete();
- } finally {
- if (fw != null) {
- try {
- fw.close();
- } catch (IOException e) {
- // ignore
- }
- }
+ try {
+ parsedConfig = ProviderConfigurationParser.parse(providerConfig);
+ } catch (Exception e) {
+ log.failedToParseProviderConfig(providerConfig.getAbsolutePath(), e);
}
- result.put("topology", topologyDescriptor);
- return result;
+ return parsedConfig;
}
-
/**
* KNOX-1136
*
@@ -292,7 +214,7 @@ public class SimpleDescriptorHandler {
*
* @return true if the credential was successfully provisioned; otherwise, false.
*/
- private static boolean provisionQueryParamEncryptionCredential(String topologyName) {
+ private static boolean provisionQueryParamEncryptionCredential(final String topologyName) {
boolean result = false;
try {
@@ -327,7 +249,7 @@ public class SimpleDescriptorHandler {
}
- private static boolean validateURL(String serviceName, String url) {
+ private static boolean validateURL(final String serviceName, final String url) {
boolean result = false;
if (url != null && !url.isEmpty()) {
@@ -343,7 +265,7 @@ public class SimpleDescriptorHandler {
}
- private static File resolveProviderConfigurationReference(String reference, File srcDirectory) {
+ private static File resolveProviderConfigurationReference(final String reference, final File srcDirectory) {
File providerConfig;
// If the reference includes a path
@@ -364,11 +286,15 @@ public class SimpleDescriptorHandler {
// Check the shared-providers config location
File sharedProvidersDir = new File(srcDirectory, "../shared-providers");
if (sharedProvidersDir.exists()) {
+ // Check if it's a valid name without the extension
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()) {
+ // Check the supported file extensions to see if the reference can be resolved
+ for (String ext : PROVIDER_CONFIG_FILE_EXTENSIONS) {
+ providerConfig = new File(sharedProvidersDir, reference + ext);
+ if (providerConfig.exists()) {
+ break;
+ }
providerConfig = null;
}
}
@@ -379,4 +305,209 @@ public class SimpleDescriptorHandler {
return providerConfig;
}
+
+ /**
+ * Generate a topology file, driven by the specified simple descriptor.
+ *
+ * @param desc The simple descriptor driving the topology generation.
+ * @param srcDirectory The source directory of the simple descriptor.
+ * @param destDirectory The destination directory for the generated topology file.
+ * @param cluster The discovery details for the referenced cluster.
+ * @param validServiceNames The validated service names.
+ * @param serviceURLs The URLs associated with the valid service names.
+ * @param serviceParams The params associated with the valid service names.
+ *
+ * @return A Map with the generated topology file and the referenced provider configuration.
+ */
+ private static Map<String, File> generateTopology(final SimpleDescriptor desc,
+ final File srcDirectory,
+ final File destDirectory,
+ final ServiceDiscovery.Cluster cluster,
+ final List<String> validServiceNames,
+ final Map<String, List<String>> serviceURLs,
+ final Map<String, Map<String, String>> serviceParams) {
+ Map<String, File> result = new HashMap<>();
+
+ BufferedWriter fw = null;
+ File topologyDescriptor = null;
+ try {
+ // Resolve and parse the referenced provider configuration
+ File providerConfigFile = resolveProviderConfigurationReference(desc.getProviderConfig(), srcDirectory);
+ ProviderConfiguration providerConfiguration = handleProviderConfiguration(desc, providerConfigFile);
+ if (providerConfiguration == null) {
+ throw new IllegalArgumentException("Invalid provider configuration.");
+ }
+ result.put(RESULT_REFERENCE, providerConfigFile);
+
+ ProviderConfiguration.Provider haProvider = null;
+ for (ProviderConfiguration.Provider provider : providerConfiguration.getProviders()) {
+ if ("ha".equals(provider.getRole())) {
+ haProvider = provider;
+ break;
+ }
+ }
+
+ // Collect HA-related service parameters
+ Map<String, ServiceDiscovery.Cluster.ZooKeeperConfig> haServiceParams = new HashMap<>();
+ if (cluster != null) {
+ if (haProvider != null) {
+ // Collect tne roles declared by the HaProvider
+ Map<String, String> haProviderParams = haProvider.getParams();
+ if (haProviderParams != null) {
+ Set<String> haProviderRoles = haProviderParams.keySet();
+ for (String haProviderRole : haProviderRoles) {
+ // For each role declared by the HaProvider, which supports ZooKeeper, try to get
+ // the ZK ensemble and namespace from the cluster.
+ ServiceDiscovery.Cluster.ZooKeeperConfig zkConfig =
+ cluster.getZooKeeperConfiguration(haProviderRole);
+ if (zkConfig != null) {
+ haServiceParams.put(haProviderRole, zkConfig);
+ }
+ }
+ }
+ }
+ }
+
+ // Generate the topology content
+ StringWriter sw = new StringWriter();
+
+ sw.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
+ sw.write("<!--==============================================-->\n");
+ sw.write("<!-- DO NOT EDIT. This is an auto-generated file. -->\n");
+ sw.write("<!--==============================================-->\n");
+
+ sw.write("<topology>\n");
+
+ // KNOX-1105 Indicate that this topology was auto-generated
+ sw.write(" <generated>true</generated>\n");
+
+ // Incorporate the externalized provider configuration content into the topology descriptor
+ sw.write(" <gateway>\n");
+ for (ProviderConfiguration.Provider provider : providerConfiguration.getProviders()) {
+ sw.write(" <provider>\n");
+ sw.write(" <role>" + provider.getRole() + "</role>\n");
+ sw.write(" <name>" + provider.getName() + "</name>\n");
+ sw.write(" <enabled>" + provider.isEnabled() + "</enabled>\n");
+
+ for (Map.Entry<String, String> param : provider.getParams().entrySet()) {
+ sw.write(" <param>\n");
+ sw.write(" <name>" + param.getKey() + "</name>\n");
+ sw.write(" <value>" + param.getValue() + "</value>\n");
+ sw.write(" </param>\n");
+ }
+
+ sw.write(" </provider>\n");
+ }
+ sw.write(" </gateway>\n");
+
+ // Services
+ // Sort the service names to write the services alphabetically
+ List<String> serviceNames = new ArrayList<>(validServiceNames);
+ Collections.sort(serviceNames);
+
+ // Write the service declarations
+ for (String serviceName : serviceNames) {
+ sw.write("\n");
+ sw.write(" <service>\n");
+ sw.write(" <role>" + serviceName + "</role>\n");
+
+ // If the service is configured for ZooKeeper-based HA
+ ServiceDiscovery.Cluster.ZooKeeperConfig zkConf = haServiceParams.get(serviceName);
+ if (zkConf != null && zkConf.isEnabled() && zkConf.getEnsemble() != null) {
+ // Add the zookeeper params to the map for serialization
+ Map<String,String> params = serviceParams.computeIfAbsent(serviceName, k -> new HashMap<>());
+
+ String ensemble = zkConf.getEnsemble();
+ if (ensemble != null) {
+ params.put("zookeeperEnsemble", ensemble);
+ }
+
+ String namespace = zkConf.getNamespace();
+ if (namespace != null) {
+ params.put("zookeeperNamespace", namespace);
+ }
+ } else {
+ // Serialize the service URLs
+ List<String> urls = serviceURLs.get(serviceName);
+ if (urls != null) {
+ for (String url : urls) {
+ sw.write(" <url>" + url + "</url>\n");
+ }
+ }
+ }
+
+ // Params
+ Map<String, String> svcParams = serviceParams.get(serviceName);
+ if (svcParams != null) {
+ for (String paramName : svcParams.keySet()) {
+ sw.write(" <param>\n");
+ sw.write(" <name>" + paramName + "</name>\n");
+ sw.write(" <value>" + svcParams.get(paramName) + "</value>\n");
+ sw.write(" </param>\n");
+ }
+ }
+
+ sw.write(" </service>\n");
+ }
+
+ // Applications
+ List<SimpleDescriptor.Application> apps = desc.getApplications();
+ if (apps != null) {
+ for (SimpleDescriptor.Application app : apps) {
+ sw.write(" <application>\n");
+ sw.write(" <name>" + app.getName() + "</name>\n");
+
+ // URLs
+ List<String> urls = app.getURLs();
+ if (urls != null) {
+ for (String url : urls) {
+ sw.write(" <url>" + url + "</url>\n");
+ }
+ }
+
+ // Params
+ Map<String, String> appParams = app.getParams();
+ if (appParams != null) {
+ for (String paramName : appParams.keySet()) {
+ sw.write(" <param>\n");
+ sw.write(" <name>" + paramName + "</name>\n");
+ sw.write(" <value>" + appParams.get(paramName) + "</value>\n");
+ sw.write(" </param>\n");
+ }
+ }
+
+ sw.write(" </application>\n");
+ }
+ }
+
+ sw.write("</topology>\n");
+
+ // Write the generated content to a file
+ String topologyFilename = desc.getName();
+ if (topologyFilename == null) {
+ topologyFilename = desc.getClusterName();
+ }
+ topologyDescriptor = new File(destDirectory, topologyFilename + ".xml");
+
+ fw = new BufferedWriter(new FileWriter(topologyDescriptor));
+ fw.write(sw.toString());
+ fw.flush();
+ } catch (IOException e) {
+ log.failedToGenerateTopologyFromSimpleDescriptor(topologyDescriptor.getName(), e);
+ topologyDescriptor.delete();
+ } finally {
+ if (fw != null) {
+ try {
+ fw.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+
+ result.put(RESULT_TOPOLOGY, topologyDescriptor);
+
+ return result;
+ }
+
}
http://git-wip-us.apache.org/repos/asf/knox/blob/7025086a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorMessages.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorMessages.java b/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorMessages.java
index 28962f9..869c27b 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorMessages.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/topology/simple/SimpleDescriptorMessages.java
@@ -37,15 +37,20 @@ public interface SimpleDescriptorMessages {
void failedToResolveProviderConfigRef(final String providerConfigRef);
@Message(level = MessageLevel.ERROR,
+ text = "Failed to parse the referenced provider configuration {0}: {1}")
+ void failedToParseProviderConfig(final String providerConfigRef,
+ @StackTrace( level = MessageLevel.DEBUG ) Exception e);
+
+ @Message(level = MessageLevel.ERROR,
text = "URL validation failed for {0} URL {1} : {2}")
void serviceURLValidationFailed(final String serviceName,
final String url,
- @StackTrace( level = MessageLevel.DEBUG ) Exception e );
+ @StackTrace( level = MessageLevel.DEBUG ) Exception e);
@Message(level = MessageLevel.ERROR,
text = "Error generating topology {0} from simple descriptor: {1}")
void failedToGenerateTopologyFromSimpleDescriptor(final String topologyFile,
- @StackTrace( level = MessageLevel.DEBUG ) Exception e );
+ @StackTrace( level = MessageLevel.DEBUG ) Exception e);
@Message( level = MessageLevel.ERROR,
text = "Error creating a password for query string encryption for {0}: {1}" )
http://git-wip-us.apache.org/repos/asf/knox/blob/7025086a/gateway-server/src/test/java/org/apache/knox/gateway/topology/discovery/test/extension/DummyServiceDiscovery.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/topology/discovery/test/extension/DummyServiceDiscovery.java b/gateway-server/src/test/java/org/apache/knox/gateway/topology/discovery/test/extension/DummyServiceDiscovery.java
index 1758d25..21883d9 100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/topology/discovery/test/extension/DummyServiceDiscovery.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/topology/discovery/test/extension/DummyServiceDiscovery.java
@@ -42,6 +42,11 @@ public class DummyServiceDiscovery implements ServiceDiscovery {
public List<String> getServiceURLs(String serviceName) {
return Collections.singletonList("http://servicehost:9999/dummy");
}
+
+ @Override
+ public ZooKeeperConfig getZooKeeperConfiguration(String serviceName) {
+ return null;
+ }
};
private static final Map<String, Cluster> CLUSTERS = new HashMap<>();
http://git-wip-us.apache.org/repos/asf/knox/blob/7025086a/gateway-server/src/test/java/org/apache/knox/gateway/topology/discovery/test/extension/PropertiesFileServiceDiscovery.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/knox/gateway/topology/discovery/test/extension/PropertiesFileServiceDiscovery.java b/gateway-server/src/test/java/org/apache/knox/gateway/topology/discovery/test/extension/PropertiesFileServiceDiscovery.java
index bd3823f..45307f1 100644
--- a/gateway-server/src/test/java/org/apache/knox/gateway/topology/discovery/test/extension/PropertiesFileServiceDiscovery.java
+++ b/gateway-server/src/test/java/org/apache/knox/gateway/topology/discovery/test/extension/PropertiesFileServiceDiscovery.java
@@ -103,6 +103,11 @@ class PropertiesFileServiceDiscovery implements ServiceDiscovery {
public List<String> getServiceURLs(String serviceName) {
return serviceURLS.get(serviceName);
}
+
+ @Override
+ public ZooKeeperConfig getZooKeeperConfiguration(String serviceName) {
+ return null; // TODO: PJZ: Implement me
+ }
}
}