KNOX-1107 - Remote Configuration Registry Client Service (Phil Zampino via lmccay)
Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/5af2413c Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/5af2413c Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/5af2413c Branch: refs/heads/KNOX-998-Package_Restructuring Commit: 5af2413c4ea4593a081e4f5ad8ba6b2d3cf78e12 Parents: 24d51ad Author: Larry McCay <[email protected]> Authored: Mon Nov 27 12:46:35 2017 -0500 Committer: Larry McCay <[email protected]> Committed: Mon Nov 27 12:46:35 2017 -0500 ---------------------------------------------------------------------- gateway-server/pom.xml | 9 + .../apache/hadoop/gateway/GatewayMessages.java | 40 +- .../gateway/config/impl/GatewayConfigImpl.java | 47 +- .../gateway/services/CLIGatewayServices.java | 10 + .../services/DefaultGatewayServices.java | 14 +- .../topology/impl/DefaultTopologyService.java | 38 +- .../DefaultConfigurationMonitorProvider.java | 31 ++ .../DefaultRemoteConfigurationMonitor.java | 163 +++++++ .../RemoteConfigurationMonitorFactory.java | 74 ++++ .../simple/SimpleDescriptorHandler.java | 1 + ...y.monitor.RemoteConfigurationMonitorProvider | 19 + .../config/impl/GatewayConfigImplTest.java | 28 ++ .../topology/DefaultTopologyServiceTest.java | 10 +- .../ZooKeeperConfigurationMonitorTest.java | 355 ++++++++++++++++ .../apache/hadoop/gateway/util/KnoxCLITest.java | 26 +- .../hadoop/gateway/websockets/BadUrlTest.java | 11 + .../gateway/websockets/WebsocketEchoTest.java | 11 + .../WebsocketMultipleConnectionTest.java | 11 + gateway-service-remoteconfig/pom.xml | 89 ++++ .../remote/RemoteConfigurationMessages.java | 46 ++ ...nfigurationRegistryClientServiceFactory.java | 41 ++ ...figurationRegistryClientServiceProvider.java | 27 ++ .../RemoteConfigurationRegistryConfig.java | 43 ++ .../DefaultRemoteConfigurationRegistries.java | 104 +++++ .../config/RemoteConfigurationRegistries.java | 33 ++ .../RemoteConfigurationRegistriesAccessor.java | 60 +++ .../RemoteConfigurationRegistriesParser.java | 48 +++ .../config/RemoteConfigurationRegistry.java | 139 ++++++ .../config/remote/zk/CuratorClientService.java | 423 ++++++++++++++++++ .../RemoteConfigurationRegistryJAASConfig.java | 169 ++++++++ .../remote/zk/ZooKeeperClientService.java | 25 ++ .../zk/ZooKeeperClientServiceProvider.java | 34 ++ ...teConfigurationRegistryClientServiceProvider | 19 + ...efaultRemoteConfigurationRegistriesTest.java | 184 ++++++++ ...teConfigurationRegistryConfigParserTest.java | 108 +++++ .../util/RemoteRegistryConfigTestUtils.java | 117 +++++ ...eConfigurationRegistryClientServiceTest.java | 424 +++++++++++++++++++ ...moteConfigurationRegistryJAASConfigTest.java | 255 +++++++++++ .../hadoop/gateway/config/GatewayConfig.java | 34 ++ .../gateway/services/GatewayServices.java | 2 + .../RemoteConfigurationRegistryClient.java | 74 ++++ ...emoteConfigurationRegistryClientService.java | 28 ++ .../monitor/RemoteConfigurationMonitor.java | 24 ++ .../RemoteConfigurationMonitorProvider.java | 34 ++ .../hadoop/gateway/GatewayTestConfig.java | 26 ++ .../java/org/apache/hadoop/test/TestUtils.java | 2 +- gateway-test/pom.xml | 6 + .../monitor/RemoteConfigurationMonitorTest.java | 397 +++++++++++++++++ pom.xml | 18 +- 49 files changed, 3918 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/pom.xml ---------------------------------------------------------------------- diff --git a/gateway-server/pom.xml b/gateway-server/pom.xml index 0c05625..0a43584 100644 --- a/gateway-server/pom.xml +++ b/gateway-server/pom.xml @@ -188,6 +188,10 @@ <artifactId>gateway-server-xforwarded-filter</artifactId> </dependency> <dependency> + <groupId>org.apache.knox</groupId> + <artifactId>gateway-service-remoteconfig</artifactId> + </dependency> + <dependency> <groupId>net.lingala.zip4j</groupId> <artifactId>zip4j</artifactId> </dependency> @@ -316,6 +320,11 @@ <artifactId>metrics-servlets</artifactId> </dependency> + <dependency> + <groupId>org.apache.curator</groupId> + <artifactId>curator-test</artifactId> + <scope>test</scope> + </dependency> </dependencies> </project> http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java index 4cb4c40..d78ef71 100644 --- a/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/GatewayMessages.java @@ -514,19 +514,57 @@ public interface GatewayMessages { void topologyPortMappingCannotFindTopology(final String topology, final int port); + @Message( level = MessageLevel.WARN, text = "There is no registry client defined for remote configuration monitoring." ) + void missingClientConfigurationForRemoteMonitoring(); + + @Message( level = MessageLevel.WARN, text = "Could not resolve a remote configuration registry client for {0}." ) + void unresolvedClientConfigurationForRemoteMonitoring(final String clientName); + @Message( level = MessageLevel.INFO, text = "Monitoring simple descriptors in directory: {0}" ) void monitoringDescriptorChangesInDirectory(String descriptorsDir); - @Message( level = MessageLevel.INFO, text = "Monitoring shared provider configurations in directory: {0}" ) void monitoringProviderConfigChangesInDirectory(String sharedProviderDir); + @Message( level = MessageLevel.ERROR, text = "Error registering listener for remote configuration path {0} : {1}" ) + void errorAddingRemoteConfigurationListenerForPath(final String path, + @StackTrace( level = MessageLevel.DEBUG ) Exception e); + + @Message( level = MessageLevel.ERROR, text = "Error unregistering listener for remote configuration path {0} : {1}" ) + void errorRemovingRemoteConfigurationListenerForPath(final String path, + @StackTrace( level = MessageLevel.DEBUG ) Exception e); + + @Message( level = MessageLevel.ERROR, text = "Error downloading remote configuration {0} : {1}" ) + void errorDownloadingRemoteConfiguration(final String path, + @StackTrace( level = MessageLevel.DEBUG ) Exception e); + @Message( level = MessageLevel.INFO, text = "Prevented deletion of shared provider configuration because there are referencing descriptors: {0}" ) void preventedDeletionOfSharedProviderConfiguration(String providerConfigurationPath); @Message( level = MessageLevel.INFO, text = "Generated topology {0} because the associated descriptor {1} changed." ) void generatedTopologyForDescriptorChange(String topologyName, String descriptorName); + @Message( level = MessageLevel.WARN, text = "An error occurred while attempting to initialize the remote configuration monitor: {0}" ) + void remoteConfigurationMonitorInitFailure(final String errorMessage, + @StackTrace( level = MessageLevel.DEBUG ) Exception e ); + + @Message( level = MessageLevel.WARN, text = "An error occurred while attempting to start the remote configuration monitor {0} : {1}" ) + void remoteConfigurationMonitorStartFailure(final String monitorType, + final String errorMessage, + @StackTrace( level = MessageLevel.DEBUG ) Exception e ); + + @Message( level = MessageLevel.INFO, text = "Starting remote configuration monitor for source {0} ..." ) + void startingRemoteConfigurationMonitor(final String address); + + @Message( level = MessageLevel.INFO, text = "Monitoring remote configuration source {0}" ) + void monitoringRemoteConfigurationSource(final String address); + + @Message( level = MessageLevel.INFO, text = "Remote configuration monitor downloaded {0} configuration file {1}" ) + void downloadedRemoteConfigFile(final String type, final String configFileName); + + @Message( level = MessageLevel.INFO, text = "Remote configuration monitor deleted {0} configuration file {1} based on remote change." ) + void deletedRemoteConfigFile(final String type, final String configFileName); + @Message( level = MessageLevel.ERROR, text = "An error occurred while processing {0} : {1}" ) void simpleDescriptorHandlingError(final String simpleDesc, @StackTrace(level = MessageLevel.DEBUG) Exception e); http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java index 4202a18..17c2552 100644 --- a/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImpl.java @@ -184,6 +184,8 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig { public static final String DEFAULT_DEPLOYMENT_DIR = "deployments"; public static final String DEFAULT_SECURITY_DIR = "security"; public static final String DEFAULT_DATA_DIR = "data"; + private static final String PROVIDERCONFIG_DIR_NAME = "shared-providers"; + private static final String DESCRIPTORS_DIR_NAME = "descriptors"; /* Websocket defaults */ public static final boolean DEFAULT_WEBSOCKET_FEATURE_ENABLED = false; @@ -214,6 +216,10 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig { private static final String CRYPTO_KEY_LENGTH = GATEWAY_CONFIG_FILE_PREFIX + ".crypto.key.length"; public static final String SERVER_HEADER_ENABLED = GATEWAY_CONFIG_FILE_PREFIX + ".server.header.enabled"; + /* @since 0.15 Remote configuration monitoring */ + static final String CONFIG_REGISTRY_PREFIX = GATEWAY_CONFIG_FILE_PREFIX + ".remote.config.registry"; + static final String REMOTE_CONFIG_MONITOR_CLIENT_NAME = GATEWAY_CONFIG_FILE_PREFIX + ".remote.config.monitor.client"; + private static List<String> DEFAULT_GLOBAL_RULES_SERVICES; @@ -264,7 +270,7 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig { } else { dataDir = get(DATA_DIR, getGatewayHomeDir() + File.separator + DEFAULT_DATA_DIR); } - return dataDir; + return FilenameUtils.normalize(dataDir); } @Override @@ -412,6 +418,16 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig { } @Override + public String getGatewayProvidersConfigDir() { + return getGatewayConfDir() + File.separator + PROVIDERCONFIG_DIR_NAME; + } + + @Override + public String getGatewayDescriptorsDir() { + return getGatewayConfDir() + File.separator + DESCRIPTORS_DIR_NAME; + } + + @Override public String getGatewayTopologyDir() { return getGatewayConfDir() + File.separator + "topologies"; } @@ -923,4 +939,33 @@ public class GatewayConfigImpl extends Configuration implements GatewayConfig { public boolean isGatewayServerHeaderEnabled() { return Boolean.parseBoolean(getVar(SERVER_HEADER_ENABLED, "true")); } + + @Override + public List<String> getRemoteRegistryConfigurationNames() { + List<String> result = new ArrayList<>(); + + // Iterate over all the properties in this configuration + for (Map.Entry<String, String> entry : this) { + String propertyName = entry.getKey(); + + // Search for all the remote config registry properties + if (propertyName.startsWith(CONFIG_REGISTRY_PREFIX)) { + String registryName = propertyName.substring(CONFIG_REGISTRY_PREFIX.length() + 1); + result.add(registryName); + } + } + + return result; + } + + @Override + public String getRemoteRegistryConfiguration(String name) { + return get(CONFIG_REGISTRY_PREFIX + "." + name ); + } + + @Override + public String getRemoteConfigurationMonitorClientName() { + return get(REMOTE_CONFIG_MONITOR_CLIENT_NAME); + } + } http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/main/java/org/apache/hadoop/gateway/services/CLIGatewayServices.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/CLIGatewayServices.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/CLIGatewayServices.java index 114aa83..74dc4d3 100644 --- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/CLIGatewayServices.java +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/CLIGatewayServices.java @@ -23,6 +23,8 @@ import org.apache.hadoop.gateway.deploy.DeploymentContext; import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor; import org.apache.hadoop.gateway.descriptor.ResourceDescriptor; import org.apache.hadoop.gateway.i18n.messages.MessagesFactory; +import org.apache.hadoop.gateway.service.config.remote.RemoteConfigurationRegistryClientServiceFactory; +import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService; import org.apache.hadoop.gateway.services.topology.impl.DefaultTopologyService; import org.apache.hadoop.gateway.services.security.impl.DefaultAliasService; import org.apache.hadoop.gateway.services.security.impl.DefaultCryptoService; @@ -71,6 +73,12 @@ public class CLIGatewayServices implements GatewayServices { DefaultTopologyService tops = new DefaultTopologyService(); tops.init( config, options ); services.put(TOPOLOGY_SERVICE, tops); + + RemoteConfigurationRegistryClientService registryClientService = + RemoteConfigurationRegistryClientServiceFactory.newInstance(config); + registryClientService.setAliasService(alias); + registryClientService.init(config, options); + services.put(REMOTE_REGISTRY_CLIENT_SERVICE, registryClientService); } public void start() throws ServiceLifecycleException { @@ -83,6 +91,8 @@ public class CLIGatewayServices implements GatewayServices { DefaultTopologyService tops = (DefaultTopologyService)services.get(TOPOLOGY_SERVICE); tops.start(); + + (services.get(REMOTE_REGISTRY_CLIENT_SERVICE)).start(); } public void stop() throws ServiceLifecycleException { http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java index 02ac154..9dca344 100644 --- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/DefaultGatewayServices.java @@ -23,6 +23,8 @@ import org.apache.hadoop.gateway.deploy.DeploymentContext; import org.apache.hadoop.gateway.descriptor.FilterParamDescriptor; import org.apache.hadoop.gateway.descriptor.ResourceDescriptor; import org.apache.hadoop.gateway.i18n.messages.MessagesFactory; +import org.apache.hadoop.gateway.service.config.remote.RemoteConfigurationRegistryClientServiceFactory; +import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService; import org.apache.hadoop.gateway.services.registry.impl.DefaultServiceDefinitionRegistry; import org.apache.hadoop.gateway.services.metrics.impl.DefaultMetricsService; import org.apache.hadoop.gateway.services.topology.impl.DefaultTopologyService; @@ -104,6 +106,12 @@ public class DefaultGatewayServices implements GatewayServices { sis.init( config, options ); services.put( SERVER_INFO_SERVICE, sis ); + RemoteConfigurationRegistryClientService registryClientService = + RemoteConfigurationRegistryClientServiceFactory.newInstance(config); + registryClientService.setAliasService(alias); + registryClientService.init(config, options); + services.put(REMOTE_REGISTRY_CLIENT_SERVICE, registryClientService); + DefaultTopologyService tops = new DefaultTopologyService(); tops.setAliasService(alias); tops.init( config, options ); @@ -117,7 +125,7 @@ public class DefaultGatewayServices implements GatewayServices { metricsService.init( config, options ); services.put( METRICS_SERVICE, metricsService ); } - + public void start() throws ServiceLifecycleException { ms.start(); @@ -132,6 +140,10 @@ public class DefaultGatewayServices implements GatewayServices { ServerInfoService sis = (ServerInfoService) services.get(SERVER_INFO_SERVICE); sis.start(); + RemoteConfigurationRegistryClientService clientService = + (RemoteConfigurationRegistryClientService)services.get(REMOTE_REGISTRY_CLIENT_SERVICE); + clientService.start(); + DefaultTopologyService tops = (DefaultTopologyService)services.get(TOPOLOGY_SERVICE); tops.start(); http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/main/java/org/apache/hadoop/gateway/services/topology/impl/DefaultTopologyService.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/topology/impl/DefaultTopologyService.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/topology/impl/DefaultTopologyService.java index 39e8029..5fc3620 100644 --- a/gateway-server/src/main/java/org/apache/hadoop/gateway/services/topology/impl/DefaultTopologyService.java +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/services/topology/impl/DefaultTopologyService.java @@ -46,6 +46,8 @@ import org.apache.hadoop.gateway.topology.TopologyListener; import org.apache.hadoop.gateway.topology.TopologyMonitor; import org.apache.hadoop.gateway.topology.TopologyProvider; import org.apache.hadoop.gateway.topology.builder.TopologyBuilder; +import org.apache.hadoop.gateway.topology.monitor.RemoteConfigurationMonitor; +import org.apache.hadoop.gateway.topology.monitor.RemoteConfigurationMonitorFactory; import org.apache.hadoop.gateway.topology.simple.SimpleDescriptorHandler; import org.apache.hadoop.gateway.topology.validation.TopologyValidator; import org.apache.hadoop.gateway.topology.xml.AmbariFormatXmlTopologyRules; @@ -101,6 +103,7 @@ public class DefaultTopologyService private volatile Map<File, Topology> topologies; private AliasService aliasService; + private RemoteConfigurationMonitor remoteMonitor = null; private Topology loadTopology(File file) throws IOException, SAXException, URISyntaxException, InterruptedException { final long TIMEOUT = 250; //ms @@ -214,6 +217,16 @@ public class DefaultTopologyService return events; } + private File calculateAbsoluteProvidersConfigDir(GatewayConfig config) { + File pcDir = new File(config.getGatewayProvidersConfigDir()); + return pcDir.getAbsoluteFile(); + } + + private File calculateAbsoluteDescriptorsDir(GatewayConfig config) { + File descDir = new File(config.getGatewayDescriptorsDir()); + return descDir.getAbsoluteFile(); + } + private File calculateAbsoluteTopologiesDir(GatewayConfig config) { File topoDir = new File(config.getGatewayTopologyDir()); topoDir = topoDir.getAbsoluteFile(); @@ -221,7 +234,7 @@ public class DefaultTopologyService } private File calculateAbsoluteConfigDir(GatewayConfig config) { - File configDir = null; + File configDir; String path = config.getGatewayConfDir(); configDir = (path != null) ? new File(path) : (new File(config.getGatewayTopologyDir())).getParentFile(); @@ -468,16 +481,32 @@ public class DefaultTopologyService @Override public void startMonitor() throws Exception { + // Start the local configuration monitors for (FileAlterationMonitor monitor : monitors) { monitor.start(); } + + // Start the remote configuration monitor, if it has been initialized + if (remoteMonitor != null) { + try { + remoteMonitor.start(); + } catch (Exception e) { + log.remoteConfigurationMonitorStartFailure(remoteMonitor.getClass().getTypeName(), e.getLocalizedMessage(), e); + } + } } @Override public void stopMonitor() throws Exception { + // Stop the local configuration monitors for (FileAlterationMonitor monitor : monitors) { monitor.stop(); } + + // Stop the remote configuration monitor, if it has been initialized + if (remoteMonitor != null) { + remoteMonitor.stop(); + } } @Override @@ -532,7 +561,7 @@ public class DefaultTopologyService public void init(GatewayConfig config, Map<String, String> options) throws ServiceLifecycleException { try { - listeners = new HashSet<>(); + listeners = new HashSet<>(); topologies = new HashMap<>(); topologiesDirectory = calculateAbsoluteTopologiesDir(config); @@ -567,6 +596,9 @@ public class DefaultTopologyService } } + // Initialize the remote configuration monitor, if it has been configured + remoteMonitor = RemoteConfigurationMonitorFactory.get(config); + } catch (IOException | SAXException io) { throw new ServiceLifecycleException(io.getMessage()); } @@ -582,7 +614,7 @@ public class DefaultTopologyService * @return A List of the Files on the directory. */ private static List<File> listFiles(File directory) { - List<File> result = null; + List<File> result; File[] files = directory.listFiles(); if (files != null) { result = Arrays.asList(files); http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultConfigurationMonitorProvider.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultConfigurationMonitorProvider.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultConfigurationMonitorProvider.java new file mode 100644 index 0000000..7b34e3d --- /dev/null +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultConfigurationMonitorProvider.java @@ -0,0 +1,31 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.hadoop.gateway.topology.monitor; + +import org.apache.hadoop.gateway.config.GatewayConfig; +import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService; + + +public class DefaultConfigurationMonitorProvider implements RemoteConfigurationMonitorProvider { + + @Override + public RemoteConfigurationMonitor newInstance(final GatewayConfig config, + final RemoteConfigurationRegistryClientService clientService) { + return new DefaultRemoteConfigurationMonitor(config, clientService); + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultRemoteConfigurationMonitor.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultRemoteConfigurationMonitor.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultRemoteConfigurationMonitor.java new file mode 100644 index 0000000..1dd71ac --- /dev/null +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/DefaultRemoteConfigurationMonitor.java @@ -0,0 +1,163 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.hadoop.gateway.topology.monitor; + +import org.apache.commons.io.FileUtils; +import org.apache.hadoop.gateway.GatewayMessages; +import org.apache.hadoop.gateway.config.GatewayConfig; +import org.apache.hadoop.gateway.i18n.messages.MessagesFactory; +import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClient.ChildEntryListener; +import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClient.EntryListener; +import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClient; +import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService; + +import java.io.File; +import java.io.IOException; +import java.util.List; + + +class DefaultRemoteConfigurationMonitor implements RemoteConfigurationMonitor { + + private static final String NODE_KNOX = "/knox"; + private static final String NODE_KNOX_CONFIG = NODE_KNOX + "/config"; + private static final String NODE_KNOX_PROVIDERS = NODE_KNOX_CONFIG + "/shared-providers"; + private static final String NODE_KNOX_DESCRIPTORS = NODE_KNOX_CONFIG + "/descriptors"; + + private static GatewayMessages log = MessagesFactory.get(GatewayMessages.class); + + private RemoteConfigurationRegistryClient client = null; + + private File providersDir; + private File descriptorsDir; + + /** + * @param config The gateway configuration + * @param registryClientService The service from which the remote registry client should be acquired. + */ + DefaultRemoteConfigurationMonitor(GatewayConfig config, + RemoteConfigurationRegistryClientService registryClientService) { + this.providersDir = new File(config.getGatewayProvidersConfigDir()); + this.descriptorsDir = new File(config.getGatewayDescriptorsDir()); + + if (registryClientService != null) { + String clientName = config.getRemoteConfigurationMonitorClientName(); + if (clientName != null) { + this.client = registryClientService.get(clientName); + if (this.client == null) { + log.unresolvedClientConfigurationForRemoteMonitoring(clientName); + } + } else { + log.missingClientConfigurationForRemoteMonitoring(); + } + } + } + + @Override + public void start() throws Exception { + if (client == null) { + throw new IllegalStateException("Failed to acquire a remote configuration registry client."); + } + + final String monitorSource = client.getAddress(); + log.startingRemoteConfigurationMonitor(monitorSource); + + // Confirm access to the remote provider configs directory znode + List<String> providerConfigs = client.listChildEntries(NODE_KNOX_PROVIDERS); + if (providerConfigs == null) { + // Either the ZNode does not exist, or there is an authentication problem + throw new IllegalStateException("Unable to access remote path: " + NODE_KNOX_PROVIDERS); + } + + // Confirm access to the remote descriptors directory znode + List<String> descriptors = client.listChildEntries(NODE_KNOX_DESCRIPTORS); + if (descriptors == null) { + // Either the ZNode does not exist, or there is an authentication problem + throw new IllegalStateException("Unable to access remote path: " + NODE_KNOX_DESCRIPTORS); + } + + // Register a listener for provider config znode additions/removals + client.addChildEntryListener(NODE_KNOX_PROVIDERS, new ConfigDirChildEntryListener(providersDir)); + + // Register a listener for descriptor znode additions/removals + client.addChildEntryListener(NODE_KNOX_DESCRIPTORS, new ConfigDirChildEntryListener(descriptorsDir)); + + log.monitoringRemoteConfigurationSource(monitorSource); + } + + + @Override + public void stop() throws Exception { + } + + + private static class ConfigDirChildEntryListener implements ChildEntryListener { + File localDir; + + ConfigDirChildEntryListener(File localDir) { + this.localDir = localDir; + } + + @Override + public void childEvent(RemoteConfigurationRegistryClient client, Type type, String path) { + File localFile = new File(localDir, path.substring(path.lastIndexOf("/") + 1)); + + switch (type) { + case REMOVED: + FileUtils.deleteQuietly(localFile); + log.deletedRemoteConfigFile(localDir.getName(), localFile.getName()); + try { + client.removeEntryListener(path); + } catch (Exception e) { + log.errorRemovingRemoteConfigurationListenerForPath(path, e); + } + break; + case ADDED: + try { + client.addEntryListener(path, new ConfigEntryListener(localDir)); + } catch (Exception e) { + log.errorAddingRemoteConfigurationListenerForPath(path, e); + } + break; + } + } + } + + private static class ConfigEntryListener implements EntryListener { + private File localDir; + + ConfigEntryListener(File localDir) { + this.localDir = localDir; + } + + @Override + public void entryChanged(RemoteConfigurationRegistryClient client, String path, byte[] data) { + File localFile = new File(localDir, path.substring(path.lastIndexOf("/"))); + if (data != null) { + try { + FileUtils.writeByteArrayToFile(localFile, data); + log.downloadedRemoteConfigFile(localDir.getName(), localFile.getName()); + } catch (IOException e) { + log.errorDownloadingRemoteConfiguration(path, e); + } + } else { + FileUtils.deleteQuietly(localFile); + log.deletedRemoteConfigFile(localDir.getName(), localFile.getName()); + } + } + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitorFactory.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitorFactory.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitorFactory.java new file mode 100644 index 0000000..4d2df45 --- /dev/null +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/monitor/RemoteConfigurationMonitorFactory.java @@ -0,0 +1,74 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.hadoop.gateway.topology.monitor; + +import org.apache.hadoop.gateway.GatewayMessages; +import org.apache.hadoop.gateway.GatewayServer; +import org.apache.hadoop.gateway.config.GatewayConfig; +import org.apache.hadoop.gateway.i18n.messages.MessagesFactory; +import org.apache.hadoop.gateway.services.GatewayServices; +import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService; + +import java.util.ServiceLoader; + +public class RemoteConfigurationMonitorFactory { + + private static final GatewayMessages log = MessagesFactory.get(GatewayMessages.class); + + private static RemoteConfigurationRegistryClientService remoteConfigRegistryClientService = null; + + public static void setClientService(RemoteConfigurationRegistryClientService clientService) { + remoteConfigRegistryClientService = clientService; + } + + private static RemoteConfigurationRegistryClientService getClientService() { + if (remoteConfigRegistryClientService == null) { + GatewayServices services = GatewayServer.getGatewayServices(); + if (services != null) { + remoteConfigRegistryClientService = services.getService(GatewayServices.REMOTE_REGISTRY_CLIENT_SERVICE); + } + } + + return remoteConfigRegistryClientService; + } + + /** + * + * @param config The GatewayConfig + * + * @return The first RemoteConfigurationMonitor extension that is found. + */ + public static RemoteConfigurationMonitor get(GatewayConfig config) { + RemoteConfigurationMonitor rcm = null; + + ServiceLoader<RemoteConfigurationMonitorProvider> providers = + ServiceLoader.load(RemoteConfigurationMonitorProvider.class); + for (RemoteConfigurationMonitorProvider provider : providers) { + try { + rcm = provider.newInstance(config, getClientService()); + if (rcm != null) { + break; + } + } catch (Exception e) { + log.remoteConfigurationMonitorInitFailure(e.getLocalizedMessage(), e); + } + } + + return rcm; + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandler.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandler.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandler.java index 089925d..d1dc11d 100644 --- a/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandler.java +++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/topology/simple/SimpleDescriptorHandler.java @@ -185,6 +185,7 @@ public class SimpleDescriptorHandler { // Write the service declarations for (String serviceName : serviceNames) { + fw.write("\n"); fw.write(" <service>\n"); fw.write(" <role>" + serviceName + "</role>\n"); http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/main/resources/META-INF/services/org.apache.hadoop.gateway.topology.monitor.RemoteConfigurationMonitorProvider ---------------------------------------------------------------------- diff --git a/gateway-server/src/main/resources/META-INF/services/org.apache.hadoop.gateway.topology.monitor.RemoteConfigurationMonitorProvider b/gateway-server/src/main/resources/META-INF/services/org.apache.hadoop.gateway.topology.monitor.RemoteConfigurationMonitorProvider new file mode 100644 index 0000000..bd4023e --- /dev/null +++ b/gateway-server/src/main/resources/META-INF/services/org.apache.hadoop.gateway.topology.monitor.RemoteConfigurationMonitorProvider @@ -0,0 +1,19 @@ +########################################################################## +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +########################################################################## + +org.apache.hadoop.gateway.topology.monitor.DefaultConfigurationMonitorProvider http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/test/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImplTest.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImplTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImplTest.java index a9347f4..cd56f11 100644 --- a/gateway-server/src/test/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImplTest.java +++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/config/impl/GatewayConfigImplTest.java @@ -11,6 +11,10 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasItems; import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertTrue; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; /** * Licensed to the Apache Software Foundation (ASF) under one @@ -217,4 +221,28 @@ public class GatewayConfigImplTest { assertThat( serverHeaderEnabled, is(false)); } + + @Test + public void testGetRemoteConfigurationRegistryNames() { + GatewayConfigImpl config = new GatewayConfigImpl(); + + List<String> registryNames = config.getRemoteRegistryConfigurationNames(); + assertNotNull(registryNames); + assertTrue(registryNames.isEmpty()); + + config.set(GatewayConfigImpl.CONFIG_REGISTRY_PREFIX + ".test1", + "type=ZooKeeper;address=host1:2181;authType=digest;principal=itsme;credentialAlias=testAlias"); + registryNames = config.getRemoteRegistryConfigurationNames(); + assertNotNull(registryNames); + assertFalse(registryNames.isEmpty()); + assertEquals(1, registryNames.size()); + + config.set(GatewayConfigImpl.CONFIG_REGISTRY_PREFIX + ".test2", + "type=ZooKeeper;address=host2:2181,host3:2181,host4:2181"); + registryNames = config.getRemoteRegistryConfigurationNames(); + assertNotNull(registryNames); + assertFalse(registryNames.isEmpty()); + assertEquals(registryNames.size(), 2); + } + } http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/test/java/org/apache/hadoop/gateway/services/topology/DefaultTopologyServiceTest.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/services/topology/DefaultTopologyServiceTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/services/topology/DefaultTopologyServiceTest.java index 2357ad6..e4a0eba 100644 --- a/gateway-server/src/test/java/org/apache/hadoop/gateway/services/topology/DefaultTopologyServiceTest.java +++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/services/topology/DefaultTopologyServiceTest.java @@ -96,6 +96,12 @@ public class DefaultTopologyServiceTest { File dir = createDir(); File topologyDir = new File(dir, "topologies"); + File descriptorsDir = new File(dir, "descriptors"); + descriptorsDir.mkdirs(); + + File sharedProvidersDir = new File(dir, "shared-providers"); + sharedProvidersDir.mkdirs(); + long time = topologyDir.lastModified(); try { createFile(topologyDir, "one.xml", "org/apache/hadoop/gateway/topology/file/topology-one.xml", time); @@ -108,7 +114,9 @@ public class DefaultTopologyServiceTest { GatewayConfig config = EasyMock.createNiceMock(GatewayConfig.class); EasyMock.expect(config.getGatewayTopologyDir()).andReturn(topologyDir.getAbsolutePath()).anyTimes(); - EasyMock.expect(config.getGatewayConfDir()).andReturn(topologyDir.getParentFile().getAbsolutePath()).anyTimes(); + EasyMock.expect(config.getGatewayConfDir()).andReturn(descriptorsDir.getParentFile().getAbsolutePath()).anyTimes(); + EasyMock.expect(config.getGatewayProvidersConfigDir()).andReturn(sharedProvidersDir.getAbsolutePath()).anyTimes(); + EasyMock.expect(config.getGatewayDescriptorsDir()).andReturn(descriptorsDir.getAbsolutePath()).anyTimes(); EasyMock.replay(config); provider.init(config, c); http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/monitor/ZooKeeperConfigurationMonitorTest.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/monitor/ZooKeeperConfigurationMonitorTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/monitor/ZooKeeperConfigurationMonitorTest.java new file mode 100644 index 0000000..1c4ed6e --- /dev/null +++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/topology/monitor/ZooKeeperConfigurationMonitorTest.java @@ -0,0 +1,355 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.hadoop.gateway.topology.monitor; + +import org.apache.commons.io.FileUtils; +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.retry.ExponentialBackoffRetry; +import org.apache.curator.test.InstanceSpec; +import org.apache.curator.test.TestingCluster; +import org.apache.hadoop.gateway.config.GatewayConfig; +import org.apache.hadoop.gateway.service.config.remote.zk.ZooKeeperClientService; +import org.apache.hadoop.gateway.service.config.remote.zk.ZooKeeperClientServiceProvider; +import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService; +import org.apache.hadoop.gateway.services.security.AliasService; +import org.apache.hadoop.test.TestUtils; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.ZooDefs; +import org.apache.zookeeper.data.ACL; +import org.easymock.EasyMock; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Test the ZooKeeperConfigMonitor WITHOUT SASL configured or znode ACLs applied. + * The implementation of the monitor is the same regardless, since the ACLs are defined by the ZooKeeper znode + * creator, and the SASL config is purely JAAS (and external to the implementation). + */ +public class ZooKeeperConfigurationMonitorTest { + + private static final String PATH_KNOX = "/knox"; + private static final String PATH_KNOX_CONFIG = PATH_KNOX + "/config"; + private static final String PATH_KNOX_PROVIDERS = PATH_KNOX_CONFIG + "/shared-providers"; + private static final String PATH_KNOX_DESCRIPTORS = PATH_KNOX_CONFIG + "/descriptors"; + + private static File testTmp; + private static File providersDir; + private static File descriptorsDir; + + private static TestingCluster zkCluster; + + private static CuratorFramework client; + + private GatewayConfig gc; + + + @BeforeClass + public static void setupSuite() throws Exception { + testTmp = TestUtils.createTempDir(ZooKeeperConfigurationMonitorTest.class.getName()); + File confDir = TestUtils.createTempDir(testTmp + "/conf"); + providersDir = TestUtils.createTempDir(confDir + "/shared-providers"); + descriptorsDir = TestUtils.createTempDir(confDir + "/descriptors"); + + configureAndStartZKCluster(); + } + + private static void configureAndStartZKCluster() throws Exception { + // Configure security for the ZK cluster instances + Map<String, Object> customInstanceSpecProps = new HashMap<>(); + customInstanceSpecProps.put("authProvider.1", "org.apache.zookeeper.server.auth.SASLAuthenticationProvider"); + customInstanceSpecProps.put("requireClientAuthScheme", "sasl"); + + // Define the test cluster + List<InstanceSpec> instanceSpecs = new ArrayList<>(); + for (int i = 0 ; i < 3 ; i++) { + InstanceSpec is = new InstanceSpec(null, -1, -1, -1, false, (i+1), -1, -1, customInstanceSpecProps); + instanceSpecs.add(is); + } + zkCluster = new TestingCluster(instanceSpecs); + + // Start the cluster + zkCluster.start(); + + // Create the client for the test cluster + client = CuratorFrameworkFactory.builder() + .connectString(zkCluster.getConnectString()) + .retryPolicy(new ExponentialBackoffRetry(100, 3)) + .build(); + assertNotNull(client); + client.start(); + + // Create the knox config paths with an ACL for the sasl user configured for the client + List<ACL> acls = new ArrayList<>(); + acls.add(new ACL(ZooDefs.Perms.ALL, ZooDefs.Ids.ANYONE_ID_UNSAFE)); + + client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).withACL(acls).forPath(PATH_KNOX_DESCRIPTORS); + assertNotNull("Failed to create node:" + PATH_KNOX_DESCRIPTORS, + client.checkExists().forPath(PATH_KNOX_DESCRIPTORS)); + client.create().creatingParentsIfNeeded().withMode(CreateMode.PERSISTENT).withACL(acls).forPath(PATH_KNOX_PROVIDERS); + assertNotNull("Failed to create node:" + PATH_KNOX_PROVIDERS, + client.checkExists().forPath(PATH_KNOX_PROVIDERS)); + } + + @AfterClass + public static void tearDownSuite() throws Exception { + // Clean up the ZK nodes, and close the client + if (client != null) { + client.delete().deletingChildrenIfNeeded().forPath(PATH_KNOX); + client.close(); + } + + // Shutdown the ZK cluster + zkCluster.close(); + + // Delete the working dir + testTmp.delete(); + } + + @Test + public void testZooKeeperConfigMonitor() throws Exception { + String configMonitorName = "remoteConfigMonitorClient"; + + // Setup the base GatewayConfig mock + gc = EasyMock.createNiceMock(GatewayConfig.class); + EasyMock.expect(gc.getGatewayProvidersConfigDir()).andReturn(providersDir.getAbsolutePath()).anyTimes(); + EasyMock.expect(gc.getGatewayDescriptorsDir()).andReturn(descriptorsDir.getAbsolutePath()).anyTimes(); + EasyMock.expect(gc.getRemoteRegistryConfigurationNames()) + .andReturn(Collections.singletonList(configMonitorName)) + .anyTimes(); + final String registryConfig = + GatewayConfig.REMOTE_CONFIG_REGISTRY_TYPE + "=" + ZooKeeperClientService.TYPE + ";" + + GatewayConfig.REMOTE_CONFIG_REGISTRY_ADDRESS + "=" + zkCluster.getConnectString(); + EasyMock.expect(gc.getRemoteRegistryConfiguration(configMonitorName)) + .andReturn(registryConfig) + .anyTimes(); + EasyMock.expect(gc.getRemoteConfigurationMonitorClientName()).andReturn(configMonitorName).anyTimes(); + EasyMock.replay(gc); + + AliasService aliasService = EasyMock.createNiceMock(AliasService.class); + EasyMock.replay(aliasService); + + RemoteConfigurationRegistryClientService clientService = (new ZooKeeperClientServiceProvider()).newInstance(); + clientService.setAliasService(aliasService); + clientService.init(gc, Collections.emptyMap()); + clientService.start(); + + DefaultRemoteConfigurationMonitor cm = new DefaultRemoteConfigurationMonitor(gc, clientService); + + try { + cm.start(); + } catch (Exception e) { + fail("Failed to start monitor: " + e.getMessage()); + } + + try { + final String pc_one_znode = getProviderPath("providers-config1.xml"); + final File pc_one = new File(providersDir, "providers-config1.xml"); + final String pc_two_znode = getProviderPath("providers-config2.xml"); + final File pc_two = new File(providersDir, "providers-config2.xml"); + + client.create().withMode(CreateMode.PERSISTENT).forPath(pc_one_znode, TEST_PROVIDERS_CONFIG_1.getBytes()); + Thread.sleep(100); + assertTrue(pc_one.exists()); + assertEquals(TEST_PROVIDERS_CONFIG_1, FileUtils.readFileToString(pc_one)); + + client.create().withMode(CreateMode.PERSISTENT).forPath(getProviderPath("providers-config2.xml"), TEST_PROVIDERS_CONFIG_2.getBytes()); + Thread.sleep(100); + assertTrue(pc_two.exists()); + assertEquals(TEST_PROVIDERS_CONFIG_2, FileUtils.readFileToString(pc_two)); + + client.setData().forPath(pc_two_znode, TEST_PROVIDERS_CONFIG_1.getBytes()); + Thread.sleep(100); + assertTrue(pc_two.exists()); + assertEquals(TEST_PROVIDERS_CONFIG_1, FileUtils.readFileToString(pc_two)); + + client.delete().forPath(pc_two_znode); + Thread.sleep(100); + assertFalse(pc_two.exists()); + + client.delete().forPath(pc_one_znode); + Thread.sleep(100); + assertFalse(pc_one.exists()); + + final String desc_one_znode = getDescriptorPath("test1.json"); + final String desc_two_znode = getDescriptorPath("test2.json"); + final String desc_three_znode = getDescriptorPath("test3.json"); + final File desc_one = new File(descriptorsDir, "test1.json"); + final File desc_two = new File(descriptorsDir, "test2.json"); + final File desc_three = new File(descriptorsDir, "test3.json"); + + client.create().withMode(CreateMode.PERSISTENT).forPath(desc_one_znode, TEST_DESCRIPTOR_1.getBytes()); + Thread.sleep(100); + assertTrue(desc_one.exists()); + assertEquals(TEST_DESCRIPTOR_1, FileUtils.readFileToString(desc_one)); + + client.create().withMode(CreateMode.PERSISTENT).forPath(desc_two_znode, TEST_DESCRIPTOR_1.getBytes()); + Thread.sleep(100); + assertTrue(desc_two.exists()); + assertEquals(TEST_DESCRIPTOR_1, FileUtils.readFileToString(desc_two)); + + client.setData().forPath(desc_two_znode, TEST_DESCRIPTOR_2.getBytes()); + Thread.sleep(100); + assertTrue(desc_two.exists()); + assertEquals(TEST_DESCRIPTOR_2, FileUtils.readFileToString(desc_two)); + + client.create().withMode(CreateMode.PERSISTENT).forPath(desc_three_znode, TEST_DESCRIPTOR_1.getBytes()); + Thread.sleep(100); + assertTrue(desc_three.exists()); + assertEquals(TEST_DESCRIPTOR_1, FileUtils.readFileToString(desc_three)); + + client.delete().forPath(desc_two_znode); + Thread.sleep(100); + assertFalse("Expected test2.json to have been deleted.", desc_two.exists()); + + client.delete().forPath(desc_three_znode); + Thread.sleep(100); + assertFalse(desc_three.exists()); + + client.delete().forPath(desc_one_znode); + Thread.sleep(100); + assertFalse(desc_one.exists()); + } finally { + cm.stop(); + } + } + + private static String getDescriptorPath(String descriptorName) { + return PATH_KNOX_DESCRIPTORS + "/" + descriptorName; + } + + private static String getProviderPath(String providerConfigName) { + return PATH_KNOX_PROVIDERS + "/" + providerConfigName; + } + + + private static final String TEST_PROVIDERS_CONFIG_1 = + "<gateway>\n" + + " <provider>\n" + + " <role>identity-assertion</role>\n" + + " <name>Default</name>\n" + + " <enabled>true</enabled>\n" + + " </provider>\n" + + " <provider>\n" + + " <role>hostmap</role>\n" + + " <name>static</name>\n" + + " <enabled>true</enabled>\n" + + " <param><name>localhost</name><value>sandbox,sandbox.hortonworks.com</value></param>\n" + + " </provider>\n" + + "</gateway>\n"; + + private static final String TEST_PROVIDERS_CONFIG_2 = + "<gateway>\n" + + " <provider>\n" + + " <role>authentication</role>\n" + + " <name>ShiroProvider</name>\n" + + " <enabled>true</enabled>\n" + + " <param>\n" + + " <name>sessionTimeout</name>\n" + + " <value>30</value>\n" + + " </param>\n" + + " <param>\n" + + " <name>main.ldapRealm</name>\n" + + " <value>org.apache.hadoop.gateway.shirorealm.KnoxLdapRealm</value>\n" + + " </param>\n" + + " <param>\n" + + " <name>main.ldapContextFactory</name>\n" + + " <value>org.apache.hadoop.gateway.shirorealm.KnoxLdapContextFactory</value>\n" + + " </param>\n" + + " <param>\n" + + " <name>main.ldapRealm.contextFactory</name>\n" + + " <value>$ldapContextFactory</value>\n" + + " </param>\n" + + " <param>\n" + + " <name>main.ldapRealm.userDnTemplate</name>\n" + + " <value>uid={0},ou=people,dc=hadoop,dc=apache,dc=org</value>\n" + + " </param>\n" + + " <param>\n" + + " <name>main.ldapRealm.contextFactory.url</name>\n" + + " <value>ldap://localhost:33389</value>\n" + + " </param>\n" + + " <param>\n" + + " <name>main.ldapRealm.contextFactory.authenticationMechanism</name>\n" + + " <value>simple</value>\n" + + " </param>\n" + + " <param>\n" + + " <name>urls./**</name>\n" + + " <value>authcBasic</value>\n" + + " </param>\n" + + " </provider>\n" + + "</gateway>\n"; + + private static final String TEST_DESCRIPTOR_1 = + "{\n" + + " \"discovery-type\":\"AMBARI\",\n" + + " \"discovery-address\":\"http://sandbox.hortonworks.com:8080\",\n" + + " \"discovery-user\":\"maria_dev\",\n" + + " \"discovery-pwd-alias\":\"sandbox.ambari.discovery.password\",\n" + + " \"provider-config-ref\":\"sandbox-providers.xml\",\n" + + " \"cluster\":\"Sandbox\",\n" + + " \"services\":[\n" + + " {\"name\":\"NODEUI\"},\n" + + " {\"name\":\"YARNUI\"},\n" + + " {\"name\":\"HDFSUI\"},\n" + + " {\"name\":\"OOZIEUI\"},\n" + + " {\"name\":\"HBASEUI\"},\n" + + " {\"name\":\"NAMENODE\"},\n" + + " {\"name\":\"JOBTRACKER\"},\n" + + " {\"name\":\"WEBHDFS\"},\n" + + " {\"name\":\"WEBHCAT\"},\n" + + " {\"name\":\"OOZIE\"},\n" + + " {\"name\":\"WEBHBASE\"},\n" + + " {\"name\":\"RESOURCEMANAGER\"},\n" + + " {\"name\":\"AMBARI\", \"urls\":[\"http://c6401.ambari.apache.org:8080\"]},\n" + + " {\"name\":\"AMBARIUI\", \"urls\":[\"http://c6401.ambari.apache.org:8080\"]}\n" + + " ]\n" + + "}\n"; + + private static final String TEST_DESCRIPTOR_2 = + "{\n" + + " \"discovery-type\":\"AMBARI\",\n" + + " \"discovery-address\":\"http://sandbox.hortonworks.com:8080\",\n" + + " \"discovery-user\":\"maria_dev\",\n" + + " \"discovery-pwd-alias\":\"sandbox.ambari.discovery.password\",\n" + + " \"provider-config-ref\":\"sandbox-providers.xml\",\n" + + " \"cluster\":\"Sandbox\",\n" + + " \"services\":[\n" + + " {\"name\":\"NAMENODE\"},\n" + + " {\"name\":\"JOBTRACKER\"},\n" + + " {\"name\":\"WEBHDFS\"},\n" + + " {\"name\":\"WEBHCAT\"},\n" + + " {\"name\":\"OOZIE\"},\n" + + " {\"name\":\"WEBHBASE\"},\n" + + " {\"name\":\"RESOURCEMANAGER\"}\n" + + " ]\n" + + "}\n"; + +} http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/test/java/org/apache/hadoop/gateway/util/KnoxCLITest.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/util/KnoxCLITest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/util/KnoxCLITest.java index 0352fa3..838f114 100644 --- a/gateway-server/src/test/java/org/apache/hadoop/gateway/util/KnoxCLITest.java +++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/util/KnoxCLITest.java @@ -20,8 +20,11 @@ package org.apache.hadoop.gateway.util; import com.mycila.xmltool.XMLDoc; import com.mycila.xmltool.XMLTag; import org.apache.commons.io.FileUtils; +import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.gateway.config.impl.GatewayConfigImpl; import org.apache.hadoop.gateway.services.GatewayServices; +import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClient; +import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService; import org.apache.hadoop.gateway.services.security.AliasService; import org.apache.hadoop.gateway.services.security.MasterService; import org.junit.Before; @@ -42,6 +45,7 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -60,7 +64,27 @@ public class KnoxCLITest { } @Test - public void testSuccessfulAlaisLifecycle() throws Exception { + public void testRemoteConfigurationRegistryClientService() throws Exception { + outContent.reset(); + KnoxCLI cli = new KnoxCLI(); + Configuration config = new GatewayConfigImpl(); + config.set("gateway.remote.config.registry.test_client", "type=ZooKeeper;address=localhost:2181"); + cli.setConf(config); + + // This is only to get the gateway services initialized + cli.run(new String[]{"version"}); + + RemoteConfigurationRegistryClientService service = + cli.getGatewayServices().getService(GatewayServices.REMOTE_REGISTRY_CLIENT_SERVICE); + assertNotNull(service); + RemoteConfigurationRegistryClient client = service.get("test_client"); + assertNotNull(client); + + assertNull(service.get("bogus")); + } + + @Test + public void testSuccessfulAliasLifecycle() throws Exception { outContent.reset(); String[] args1 = {"create-alias", "alias1", "--value", "testvalue1", "--master", "master"}; int rc = 0; http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/BadUrlTest.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/BadUrlTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/BadUrlTest.java index 559b2a1..c465585 100644 --- a/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/BadUrlTest.java +++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/BadUrlTest.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.net.URI; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -205,6 +206,12 @@ public class BadUrlTest { EasyMock.expect(gatewayConfig.getGatewayTopologyDir()) .andReturn(topoDir.toString()).anyTimes(); + EasyMock.expect(gatewayConfig.getGatewayProvidersConfigDir()) + .andReturn(topoDir.getAbsolutePath() + "/shared-providers").anyTimes(); + + EasyMock.expect(gatewayConfig.getGatewayDescriptorsDir()) + .andReturn(topoDir.getAbsolutePath() + "/descriptors").anyTimes(); + EasyMock.expect(gatewayConfig.getGatewayServicesDir()) .andReturn(serviceUrl.getFile()).anyTimes(); @@ -247,6 +254,10 @@ public class BadUrlTest { EasyMock.expect(gatewayConfig.getWebsocketIdleTimeout()) .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_IDLE_TIMEOUT).anyTimes(); + EasyMock.expect(gatewayConfig.getRemoteRegistryConfigurationNames()) + .andReturn(Collections.emptyList()) + .anyTimes(); + EasyMock.replay(gatewayConfig); try { http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/WebsocketEchoTest.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/WebsocketEchoTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/WebsocketEchoTest.java index 4b0fe08..5d5f280 100644 --- a/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/WebsocketEchoTest.java +++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/WebsocketEchoTest.java @@ -26,6 +26,7 @@ import java.io.IOException; import java.net.URI; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -290,6 +291,12 @@ public class WebsocketEchoTest { EasyMock.expect(gatewayConfig.getGatewayTopologyDir()) .andReturn(topoDir.toString()).anyTimes(); + EasyMock.expect(gatewayConfig.getGatewayProvidersConfigDir()) + .andReturn(topoDir.getAbsolutePath() + "/shared-providers").anyTimes(); + + EasyMock.expect(gatewayConfig.getGatewayDescriptorsDir()) + .andReturn(topoDir.getAbsolutePath() + "/descriptors").anyTimes(); + EasyMock.expect(gatewayConfig.getGatewayServicesDir()) .andReturn(serviceUrl.getFile()).anyTimes(); @@ -332,6 +339,10 @@ public class WebsocketEchoTest { EasyMock.expect(gatewayConfig.getWebsocketIdleTimeout()) .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_IDLE_TIMEOUT).anyTimes(); + EasyMock.expect(gatewayConfig.getRemoteRegistryConfigurationNames()) + .andReturn(Collections.emptyList()) + .anyTimes(); + EasyMock.replay(gatewayConfig); try { http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/WebsocketMultipleConnectionTest.java ---------------------------------------------------------------------- diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/WebsocketMultipleConnectionTest.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/WebsocketMultipleConnectionTest.java index 676c98c..7ddada2 100644 --- a/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/WebsocketMultipleConnectionTest.java +++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/websockets/WebsocketMultipleConnectionTest.java @@ -25,6 +25,7 @@ import java.lang.management.MemoryMXBean; import java.net.URI; import java.net.URL; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -283,6 +284,12 @@ public class WebsocketMultipleConnectionTest { EasyMock.expect(gatewayConfig.getGatewayTopologyDir()) .andReturn(topoDir.toString()).anyTimes(); + EasyMock.expect(gatewayConfig.getGatewayProvidersConfigDir()) + .andReturn(topoDir.getAbsolutePath() + "/shared-providers").anyTimes(); + + EasyMock.expect(gatewayConfig.getGatewayDescriptorsDir()) + .andReturn(topoDir.getAbsolutePath() + "/descriptors").anyTimes(); + EasyMock.expect(gatewayConfig.getGatewayServicesDir()) .andReturn(serviceUrl.getFile()).anyTimes(); @@ -325,6 +332,10 @@ public class WebsocketMultipleConnectionTest { EasyMock.expect(gatewayConfig.getWebsocketIdleTimeout()) .andReturn(GatewayConfigImpl.DEFAULT_WEBSOCKET_IDLE_TIMEOUT).anyTimes(); + EasyMock.expect(gatewayConfig.getRemoteRegistryConfigurationNames()) + .andReturn(Collections.emptyList()) + .anyTimes(); + EasyMock.replay(gatewayConfig); try { http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-service-remoteconfig/pom.xml ---------------------------------------------------------------------- diff --git a/gateway-service-remoteconfig/pom.xml b/gateway-service-remoteconfig/pom.xml new file mode 100644 index 0000000..8d06360 --- /dev/null +++ b/gateway-service-remoteconfig/pom.xml @@ -0,0 +1,89 @@ +<?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.0.0-SNAPSHOT</version> + </parent> + <artifactId>gateway-service-remoteconfig</artifactId> + + <name>gateway-service-remoteconfig</name> + <description>The gateway service for interacting with remote configuration registries.</description> + + <licenses> + <license> + <name>The Apache Software License, Version 2.0</name> + <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> + <distribution>repo</distribution> + </license> + </licenses> + + <dependencies> + <dependency> + <groupId>${gateway-group}</groupId> + <artifactId>gateway-spi</artifactId> + </dependency> + + <dependency> + <groupId>org.apache.zookeeper</groupId> + <artifactId>zookeeper</artifactId> + </dependency> + <dependency> + <groupId>org.apache.curator</groupId> + <artifactId>curator-framework</artifactId> + </dependency> + <dependency> + <groupId>org.apache.curator</groupId> + <artifactId>curator-client</artifactId> + </dependency> + + <dependency> + <groupId>${gateway-group}</groupId> + <artifactId>gateway-test-utils</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.easymock</groupId> + <artifactId>easymock</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.curator</groupId> + <artifactId>curator-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.curator</groupId> + <artifactId>curator-test</artifactId> + <scope>test</scope> + </dependency> + + </dependencies> + +</project> http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationMessages.java ---------------------------------------------------------------------- diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationMessages.java b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationMessages.java new file mode 100644 index 0000000..22e622d --- /dev/null +++ b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationMessages.java @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.hadoop.gateway.service.config.remote; + +import org.apache.hadoop.gateway.i18n.messages.Message; +import org.apache.hadoop.gateway.i18n.messages.MessageLevel; +import org.apache.hadoop.gateway.i18n.messages.Messages; +import org.apache.hadoop.gateway.i18n.messages.StackTrace; + + +/** + * + */ +@Messages(logger="org.apache.hadoop.gateway.service.config.remote") +public interface RemoteConfigurationMessages { + + @Message(level = MessageLevel.WARN, + text = "Multiple remote configuration registries are not currently supported if any of them requires authentication.") + void multipleRemoteRegistryConfigurations(); + + @Message(level = MessageLevel.ERROR, text = "Failed to resolve the credential alias {0}") + void unresolvedCredentialAlias(final String alias); + + @Message(level = MessageLevel.ERROR, text = "An error occurred interacting with the remote configuration registry : {0}") + void errorInteractingWithRemoteConfigRegistry(@StackTrace(level = MessageLevel.DEBUG) Exception e); + + @Message(level = MessageLevel.ERROR, text = "An error occurred handling the ACL for remote configuration {0} : {1}") + void errorHandlingRemoteConfigACL(final String path, + @StackTrace(level = MessageLevel.DEBUG) Exception e); + + +} http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceFactory.java ---------------------------------------------------------------------- diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceFactory.java b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceFactory.java new file mode 100644 index 0000000..cd58e22 --- /dev/null +++ b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceFactory.java @@ -0,0 +1,41 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.hadoop.gateway.service.config.remote; + +import org.apache.hadoop.gateway.config.GatewayConfig; +import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService; + +import java.util.ServiceLoader; + +public class RemoteConfigurationRegistryClientServiceFactory { + + public static RemoteConfigurationRegistryClientService newInstance(GatewayConfig config) { + RemoteConfigurationRegistryClientService rcs = null; + + ServiceLoader<RemoteConfigurationRegistryClientServiceProvider> providers = + ServiceLoader.load(RemoteConfigurationRegistryClientServiceProvider.class); + for (RemoteConfigurationRegistryClientServiceProvider provider : providers) { + rcs = provider.newInstance(); + if (rcs != null) { + break; + } + } + + return rcs; + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceProvider.java ---------------------------------------------------------------------- diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceProvider.java b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceProvider.java new file mode 100644 index 0000000..ddfc392 --- /dev/null +++ b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationRegistryClientServiceProvider.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.hadoop.gateway.service.config.remote; + +import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService; + +public interface RemoteConfigurationRegistryClientServiceProvider { + + String getType(); + + RemoteConfigurationRegistryClientService newInstance(); + +} http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationRegistryConfig.java ---------------------------------------------------------------------- diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationRegistryConfig.java b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationRegistryConfig.java new file mode 100644 index 0000000..6409250 --- /dev/null +++ b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/RemoteConfigurationRegistryConfig.java @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.hadoop.gateway.service.config.remote; + +public interface RemoteConfigurationRegistryConfig { + + String getName(); + + String getRegistryType(); + + String getConnectionString(); + + String getNamespace(); + + boolean isSecureRegistry(); + + String getAuthType(); // digest, kerberos, etc... + + String getPrincipal(); + + String getCredentialAlias(); + + String getKeytab(); + + boolean isUseTicketCache(); + + boolean isUseKeyTab(); + +} http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/config/DefaultRemoteConfigurationRegistries.java ---------------------------------------------------------------------- diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/config/DefaultRemoteConfigurationRegistries.java b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/config/DefaultRemoteConfigurationRegistries.java new file mode 100644 index 0000000..ebcae1b --- /dev/null +++ b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/config/DefaultRemoteConfigurationRegistries.java @@ -0,0 +1,104 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.hadoop.gateway.service.config.remote.config; + +import org.apache.hadoop.gateway.config.GatewayConfig; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A set of RemoteConfigurationRegistry configurations based on a set of property name-value pairs. + */ +class DefaultRemoteConfigurationRegistries extends RemoteConfigurationRegistries { + + private static final String PROPERTY_DELIM = ";"; + private static final String PROPERTY_VALUE_DELIM = "="; + + private List<RemoteConfigurationRegistry> configuredRegistries = new ArrayList<>(); + + /** + * Derive the remote registry configurations from the specified GatewayConfig. + * + * @param gc The source GatewayConfig + */ + DefaultRemoteConfigurationRegistries(GatewayConfig gc) { + List<String> configRegistryNames = gc.getRemoteRegistryConfigurationNames(); + for (String configRegistryName : configRegistryNames) { + configuredRegistries.add(extractConfigForRegistry(gc, configRegistryName)); + } + } + + /** + * Extract the configuration for the specified registry configuration name. + * + * @param gc The GatewayConfig from which to extract the registry config. + * @param registryName The name of the registry config. + * + * @return The resulting RemoteConfigurationRegistry object, or null. + */ + private static RemoteConfigurationRegistry extractConfigForRegistry(GatewayConfig gc, String registryName) { + RemoteConfigurationRegistry result = new RemoteConfigurationRegistry(); + + result.setName(registryName); + + Map<String, String> properties = parsePropertyValue(gc.getRemoteRegistryConfiguration(registryName)); + + result.setRegistryType(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_TYPE)); + result.setConnectionString(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_ADDRESS)); + result.setNamespace(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_NAMESPACE)); + result.setAuthType(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_AUTH_TYPE)); + result.setPrincipal(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_PRINCIPAL)); + result.setCredentialAlias(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_CREDENTIAL_ALIAS)); + result.setKeytab(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_KEYTAB)); + result.setUseKeytab(Boolean.valueOf(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_USE_KEYTAB))); + result.setUseTicketCache(Boolean.valueOf(properties.get(GatewayConfig.REMOTE_CONFIG_REGISTRY_USE_TICKET_CACHE))); + + return result; + } + + /** + * Parse the specified registry config properties String. + * + * @param value The property value content from GatewayConfig. + * + * @return A Map of the parsed properties and their respective values. + */ + private static Map<String, String> parsePropertyValue(final String value) { + Map<String, String> result = new HashMap<>(); + + if (value != null) { + String[] props = value.split(PROPERTY_DELIM); + for (String prop : props) { + String[] split = prop.split(PROPERTY_VALUE_DELIM); + String propName = split[0]; + String propValue = (split.length > 1) ? split[1] : null; + result.put(propName, propValue); + } + } + + return result; + } + + @Override + List<RemoteConfigurationRegistry> getRegistryConfigurations() { + return configuredRegistries; + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/5af2413c/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/config/RemoteConfigurationRegistries.java ---------------------------------------------------------------------- diff --git a/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/config/RemoteConfigurationRegistries.java b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/config/RemoteConfigurationRegistries.java new file mode 100644 index 0000000..fa045c0 --- /dev/null +++ b/gateway-service-remoteconfig/src/main/java/org/apache/hadoop/gateway/service/config/remote/config/RemoteConfigurationRegistries.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package org.apache.hadoop.gateway.service.config.remote.config; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.util.ArrayList; +import java.util.List; + +@XmlRootElement(name="remote-configuration-registries") +class RemoteConfigurationRegistries { + + private List<RemoteConfigurationRegistry> registryConfigurations = new ArrayList<>(); + + @XmlElement(name="remote-configuration-registry") + List<RemoteConfigurationRegistry> getRegistryConfigurations() { + return registryConfigurations; + } +}
