You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2017/12/14 21:13:10 UTC
[23/49] knox git commit: KNOX-1125 - KNOXCLI Additions to Support
Management of Knox config in remote registry (Phil Zampino via Sandeep More)
KNOX-1125 - KNOXCLI Additions to Support Management of Knox config in remote registry (Phil Zampino via Sandeep More)
Project: http://git-wip-us.apache.org/repos/asf/knox/repo
Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/828ea38f
Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/828ea38f
Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/828ea38f
Branch: refs/heads/KNOX-998-Package_Restructuring
Commit: 828ea38fcfd4a4edee2813ae9d357ee0f555afc8
Parents: a09e751
Author: Sandeep More <mo...@apache.org>
Authored: Mon Dec 4 13:44:04 2017 -0500
Committer: Sandeep More <mo...@apache.org>
Committed: Mon Dec 4 13:44:04 2017 -0500
----------------------------------------------------------------------
.../DefaultRemoteConfigurationMonitor.java | 2 +
.../org/apache/hadoop/gateway/util/KnoxCLI.java | 391 ++++++++++++++++++-
...emoteConfigurationRegistryClientService.java | 243 ++++++++++++
...figurationRegistryClientServiceProvider.java | 32 ++
.../apache/hadoop/gateway/util/KnoxCLITest.java | 361 ++++++++++++++++-
...teConfigurationRegistryClientServiceProvider | 19 +
6 files changed, 1039 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/knox/blob/828ea38f/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
index 1dd71ac..03bbf16 100644
--- 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
@@ -101,6 +101,8 @@ class DefaultRemoteConfigurationMonitor implements RemoteConfigurationMonitor {
@Override
public void stop() throws Exception {
+ client.removeEntryListener(NODE_KNOX_PROVIDERS);
+ client.removeEntryListener(NODE_KNOX_DESCRIPTORS);
}
http://git-wip-us.apache.org/repos/asf/knox/blob/828ea38f/gateway-server/src/main/java/org/apache/hadoop/gateway/util/KnoxCLI.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/main/java/org/apache/hadoop/gateway/util/KnoxCLI.java b/gateway-server/src/main/java/org/apache/hadoop/gateway/util/KnoxCLI.java
index afc6ee0..5576df7 100644
--- a/gateway-server/src/main/java/org/apache/hadoop/gateway/util/KnoxCLI.java
+++ b/gateway-server/src/main/java/org/apache/hadoop/gateway/util/KnoxCLI.java
@@ -20,7 +20,6 @@ package org.apache.hadoop.gateway.util;
import java.io.BufferedReader;
import java.io.Console;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -28,7 +27,6 @@ import java.io.PrintStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
@@ -51,6 +49,8 @@ import org.apache.hadoop.gateway.services.CLIGatewayServices;
import org.apache.hadoop.gateway.services.GatewayServices;
import org.apache.hadoop.gateway.services.Service;
import org.apache.hadoop.gateway.services.ServiceLifecycleException;
+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.KeystoreService;
import org.apache.hadoop.gateway.services.security.KeystoreServiceException;
@@ -82,6 +82,7 @@ import org.apache.shiro.util.ThreadContext;
import org.eclipse.persistence.oxm.MediaType;
import org.jboss.shrinkwrap.api.exporter.ExplodedExporter;
import org.jboss.shrinkwrap.api.spec.EnterpriseArchive;
+
/**
*
*/
@@ -102,7 +103,13 @@ public class KnoxCLI extends Configured implements Tool {
" [" + ValidateTopologyCommand.USAGE + "]\n" +
" [" + LDAPAuthCommand.USAGE + "]\n" +
" [" + LDAPSysBindCommand.USAGE + "]\n" +
- " [" + ServiceTestCommand.USAGE + "]\n";
+ " [" + ServiceTestCommand.USAGE + "]\n" +
+ " [" + RemoteRegistryClientsListCommand.USAGE + "]\n" +
+ " [" + RemoteRegistryUploadProviderConfigCommand.USAGE + "]\n" +
+ " [" + RemoteRegistryUploadDescriptorCommand.USAGE + "]\n" +
+ " [" + RemoteRegistryDeleteProviderConfigCommand.USAGE + "]\n" +
+ " [" + RemoteRegistryDeleteDescriptorCommand.USAGE + "]\n" +
+ " [" + RemoteRegistryGetACLCommand.USAGE + "]\n";
/** allows stdout to be captured if necessary */
public PrintStream out = System.out;
@@ -123,6 +130,9 @@ public class KnoxCLI extends Configured implements Tool {
private String pass = null;
private boolean groups = false;
+ private String remoteRegistryClient = null;
+ private String remoteRegistryEntryName = null;
+
// For testing only
private String master = null;
private String type = null;
@@ -187,7 +197,12 @@ public class KnoxCLI extends Configured implements Tool {
* % knoxcli user-auth-test [--cluster clustername] [--u username] [--p password]
* % knoxcli system-user-auth-test [--cluster clustername] [--d]
* % knoxcli service-test [--u user] [--p password] [--cluster clustername] [--hostname name] [--port port]
- *
+ * % knoxcli list-registry-clients
+ * % knoxcli get-registry-acl entryName --registry-client name
+ * % knoxcli upload-provider-config filePath --registry-client name [--entry-name entryName]
+ * % knoxcli upload-descriptor filePath --registry-client name [--entry-name entryName]
+ * % knoxcli delete-provider-config providerConfig --registry-client name
+ * % knoxcli delete-descriptor descriptor --registry-client name
* </pre>
* @param args
* @return
@@ -282,7 +297,7 @@ public class KnoxCLI extends Configured implements Tool {
}
this.cluster = args[++i];
} else if (args[i].equals("service-test")) {
- if( i + 1 >= args[i].length()) {
+ if( i + 1 >= args.length) {
printKnoxShellUsage();
return -1;
} else {
@@ -348,6 +363,63 @@ public class KnoxCLI extends Configured implements Tool {
}
} else if (args[i].equals("--g")) {
this.groups = true;
+ } else if (args[i].equals("list-registry-clients")) {
+ command = new RemoteRegistryClientsListCommand();
+ } else if (args[i].equals("--registry-client")) {
+ if (i + 1 >= args.length || args[i + 1].startsWith("-")) {
+ printKnoxShellUsage();
+ return -1;
+ }
+ this.remoteRegistryClient = args[++i];
+ } else if (args[i].equalsIgnoreCase("upload-provider-config")) {
+ String fileName;
+ if (i <= (args.length - 1)) {
+ fileName = args[++i];
+ command = new RemoteRegistryUploadProviderConfigCommand(fileName);
+ } else {
+ printKnoxShellUsage();
+ return -1;
+ }
+ } else if (args[i].equals("upload-descriptor")) {
+ String fileName;
+ if (i <= (args.length - 1)) {
+ fileName = args[++i];
+ command = new RemoteRegistryUploadDescriptorCommand(fileName);
+ } else {
+ printKnoxShellUsage();
+ return -1;
+ }
+ } else if (args[i].equals("--entry-name")) {
+ if (i <= (args.length - 1)) {
+ remoteRegistryEntryName = args[++i];
+ } else {
+ printKnoxShellUsage();
+ return -1;
+ }
+ } else if (args[i].equals("delete-descriptor")) {
+ if (i <= (args.length - 1)) {
+ String entry = args[++i];
+ command = new RemoteRegistryDeleteDescriptorCommand(entry);
+ } else {
+ printKnoxShellUsage();
+ return -1;
+ }
+ } else if (args[i].equals("delete-provider-config")) {
+ if (i <= (args.length - 1)) {
+ String entry = args[++i];
+ command = new RemoteRegistryDeleteProviderConfigCommand(entry);
+ } else {
+ printKnoxShellUsage();
+ return -1;
+ }
+ } else if (args[i].equalsIgnoreCase("get-registry-acl")) {
+ if (i <= (args.length - 1)) {
+ String entry = args[++i];
+ command = new RemoteRegistryGetACLCommand(entry);
+ } else {
+ printKnoxShellUsage();
+ return -1;
+ }
} else {
printKnoxShellUsage();
//ToolRunner.printGenericCommandUsage(System.err);
@@ -406,6 +478,24 @@ public class KnoxCLI extends Configured implements Tool {
out.println(ServiceTestCommand.USAGE + "\n\n" + ServiceTestCommand.DESC);
out.println();
out.println( div );
+ out.println(RemoteRegistryClientsListCommand.USAGE + "\n\n" + RemoteRegistryClientsListCommand.DESC);
+ out.println();
+ out.println( div );
+ out.println(RemoteRegistryGetACLCommand.USAGE + "\n\n" + RemoteRegistryGetACLCommand.DESC);
+ out.println();
+ out.println( div );
+ out.println(RemoteRegistryUploadProviderConfigCommand.USAGE + "\n\n" + RemoteRegistryUploadProviderConfigCommand.DESC);
+ out.println();
+ out.println( div );
+ out.println(RemoteRegistryUploadDescriptorCommand.USAGE + "\n\n" + RemoteRegistryUploadDescriptorCommand.DESC);
+ out.println();
+ out.println( div );
+ out.println(RemoteRegistryDeleteProviderConfigCommand.USAGE + "\n\n" + RemoteRegistryDeleteProviderConfigCommand.DESC);
+ out.println();
+ out.println( div );
+ out.println(RemoteRegistryDeleteDescriptorCommand.USAGE + "\n\n" + RemoteRegistryDeleteDescriptorCommand.DESC);
+ out.println();
+ out.println( div );
}
}
@@ -439,6 +529,11 @@ public class KnoxCLI extends Configured implements Tool {
TopologyService ts = services.getService(GatewayServices.TOPOLOGY_SERVICE);
return ts;
}
+
+ protected RemoteConfigurationRegistryClientService getRemoteConfigRegistryClientService() {
+ return services.getService(GatewayServices.REMOTE_REGISTRY_CLIENT_SERVICE);
+ }
+
}
private class AliasListCommand extends Command {
@@ -1598,9 +1693,10 @@ public class KnoxCLI extends Configured implements Tool {
public class ServiceTestCommand extends Command {
public static final String USAGE = "service-test [--u username] [--p password] [--cluster clustername] [--hostname name] " +
"[--port port]";
- public static final String DESC = "This command requires a running instance of Knox to be present on the same " +
- "machine. It will execute a test to make sure all services are accessible through the gateway URLs. Errors are " +
- "reported and suggestions to resolve any problems are returned. JSON formatted.";
+ public static final String DESC =
+ "This command requires a running instance of Knox to be present on the same machine.\n" +
+ "It will execute a test to make sure all services are accessible through the gateway URLs.\n" +
+ "Errors are reported and suggestions to resolve any problems are returned. JSON formatted.\n";
private boolean ssl = true;
private int attempts = 0;
@@ -1753,6 +1849,285 @@ public class KnoxCLI extends Configured implements Tool {
}
+ public class RemoteRegistryClientsListCommand extends Command {
+
+ static final String USAGE = "list-registry-clients";
+ static final String DESC = "Lists all of the remote configuration registry clients defined in gateway-site.xml.\n";
+
+ /* (non-Javadoc)
+ * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#execute()
+ */
+ @Override
+ public void execute() throws Exception {
+ GatewayConfig config = getGatewayConfig();
+ List<String> remoteConfigRegistryClientNames = config.getRemoteRegistryConfigurationNames();
+ if (!remoteConfigRegistryClientNames.isEmpty()) {
+ out.println("Listing remote configuration registry clients:");
+ for (String name : remoteConfigRegistryClientNames) {
+ out.println(name);
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#getUsage()
+ */
+ @Override
+ public String getUsage() {
+ return USAGE + ":\n\n" + DESC;
+ }
+ }
+
+
+ /**
+ * Base class for remote config registry upload commands
+ */
+ public abstract class RemoteRegistryUploadCommand extends Command {
+ protected static final String ROOT_ENTRY = "/knox";
+ protected static final String CONFIG_ENTRY = ROOT_ENTRY + "/config";
+ protected static final String PROVIDER_CONFIG_ENTRY = CONFIG_ENTRY + "/shared-providers";
+ protected static final String DESCRIPTORS__ENTRY = CONFIG_ENTRY + "/descriptors";
+
+ private File sourceFile = null;
+ protected String filename = null;
+
+ protected RemoteRegistryUploadCommand(String sourceFileName) {
+ this.filename = sourceFileName;
+ }
+
+ private void upload(RemoteConfigurationRegistryClient client, String entryPath, File source) throws Exception {
+ String content = FileUtils.readFileToString(source);
+ if (client.entryExists(entryPath)) {
+ // If it exists, then we're going to set the data
+ client.setEntryData(entryPath, content);
+ } else {
+ // If it does not exist, then create it and set the data
+ client.createEntry(entryPath, content);
+ }
+ }
+
+ File getSourceFile() {
+ if (sourceFile == null) {
+ sourceFile = new File(filename);
+ }
+ return sourceFile;
+ }
+
+ String getEntryName(String prefixPath) {
+ String entryName = remoteRegistryEntryName;
+ if (entryName == null) {
+ File sourceFile = getSourceFile();
+ if (sourceFile.exists()) {
+ String path = sourceFile.getAbsolutePath();
+ entryName = path.substring(path.lastIndexOf(File.separator) + 1);
+ } else {
+ out.println("Could not locate source file: " + filename);
+ }
+ }
+ return prefixPath + "/" + entryName;
+ }
+
+ protected void execute(String entryName, File sourceFile) throws Exception {
+ if (remoteRegistryClient != null) {
+ RemoteConfigurationRegistryClientService cs = getRemoteConfigRegistryClientService();
+ RemoteConfigurationRegistryClient client = cs.get(remoteRegistryClient);
+ if (client != null) {
+ if (entryName != null) {
+ upload(client, entryName, sourceFile);
+ }
+ } else {
+ out.println("No remote configuration registry identified by '" + remoteRegistryClient + "' could be found.");
+ }
+ } else {
+ out.println("Missing required argument : --registry-client\n");
+ }
+ }
+
+ }
+
+
+ public class RemoteRegistryUploadProviderConfigCommand extends RemoteRegistryUploadCommand {
+
+ static final String USAGE = "upload-provider-config providerConfigFile --registry-client name [--entry-name entryName]";
+ static final String DESC = "Uploads a provider configuration to the specified remote registry client, optionally " +
+ "renaming the entry.\nIf the entry name is not specified, the name of the uploaded " +
+ "file is used.\n";
+
+ RemoteRegistryUploadProviderConfigCommand(String fileName) {
+ super(fileName);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#execute()
+ */
+ @Override
+ public void execute() throws Exception {
+ super.execute(getEntryName(PROVIDER_CONFIG_ENTRY), getSourceFile());
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#getUsage()
+ */
+ @Override
+ public String getUsage() {
+ return USAGE + ":\n\n" + DESC;
+ }
+ }
+
+
+ public class RemoteRegistryUploadDescriptorCommand extends RemoteRegistryUploadCommand {
+
+ static final String USAGE = "upload-descriptor descriptorFile --registry-client name [--entry-name entryName]";
+ static final String DESC = "Uploads a simple descriptor using the specified remote registry client, optionally " +
+ "renaming the entry.\nIf the entry name is not specified, the name of the uploaded " +
+ "file is used.\n";
+
+ RemoteRegistryUploadDescriptorCommand(String fileName) {
+ super(fileName);
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#execute()
+ */
+ @Override
+ public void execute() throws Exception {
+ super.execute(getEntryName(DESCRIPTORS__ENTRY), getSourceFile());
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#getUsage()
+ */
+ @Override
+ public String getUsage() {
+ return USAGE + ":\n\n" + DESC;
+ }
+ }
+
+
+ public class RemoteRegistryGetACLCommand extends Command {
+
+ static final String USAGE = "get-registry-acl entry --registry-client name";
+ static final String DESC = "Presents the ACL settings for the specified remote registry entry.\n";
+
+ private String entry = null;
+
+ RemoteRegistryGetACLCommand(String entry) {
+ this.entry = entry;
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#execute()
+ */
+ @Override
+ public void execute() throws Exception {
+ if (remoteRegistryClient != null) {
+ RemoteConfigurationRegistryClientService cs = getRemoteConfigRegistryClientService();
+ RemoteConfigurationRegistryClient client = cs.get(remoteRegistryClient);
+ if (client != null) {
+ if (entry != null) {
+ List<RemoteConfigurationRegistryClient.EntryACL> acls = client.getACL(entry);
+ for (RemoteConfigurationRegistryClient.EntryACL acl : acls) {
+ out.println(acl.getType() + ":" + acl.getId() + ":" + acl.getPermissions());
+ }
+ }
+ } else {
+ out.println("No remote configuration registry identified by '" + remoteRegistryClient + "' could be found.");
+ }
+ } else {
+ out.println("Missing required argument : --registry-client\n");
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.hadoop.gateway.util.KnoxCLI.Command#getUsage()
+ */
+ @Override
+ public String getUsage() {
+ return USAGE + ":\n\n" + DESC;
+ }
+ }
+
+
+ /**
+ * Base class for remote config registry delete commands
+ */
+ public abstract class RemoteRegistryDeleteCommand extends Command {
+ protected static final String ROOT_ENTRY = "/knox";
+ protected static final String CONFIG_ENTRY = ROOT_ENTRY + "/config";
+ protected static final String PROVIDER_CONFIG_ENTRY = CONFIG_ENTRY + "/shared-providers";
+ protected static final String DESCRIPTORS__ENTRY = CONFIG_ENTRY + "/descriptors";
+
+ protected String entryName = null;
+
+ protected RemoteRegistryDeleteCommand(String entryName) {
+ this.entryName = entryName;
+ }
+
+ private void delete(RemoteConfigurationRegistryClient client, String entryPath) throws Exception {
+ if (client.entryExists(entryPath)) {
+ // If it exists, then delete it
+ client.deleteEntry(entryPath);
+ }
+ }
+
+ protected void execute(String entryName) throws Exception {
+ if (remoteRegistryClient != null) {
+ RemoteConfigurationRegistryClientService cs = getRemoteConfigRegistryClientService();
+ RemoteConfigurationRegistryClient client = cs.get(remoteRegistryClient);
+ if (client != null) {
+ if (entryName != null) {
+ delete(client, entryName);
+ }
+ } else {
+ out.println("No remote configuration registry identified by '" + remoteRegistryClient + "' could be found.");
+ }
+ } else {
+ out.println("Missing required argument : --registry-client\n");
+ }
+ }
+ }
+
+
+ public class RemoteRegistryDeleteProviderConfigCommand extends RemoteRegistryDeleteCommand {
+ static final String USAGE = "delete-provider-config providerConfig --registry-client name";
+ static final String DESC = "Deletes a shared provider configuration from the specified remote registry.\n";
+
+ public RemoteRegistryDeleteProviderConfigCommand(String entryName) {
+ super(entryName);
+ }
+
+ @Override
+ public void execute() throws Exception {
+ execute(PROVIDER_CONFIG_ENTRY + "/" + entryName);
+ }
+
+ @Override
+ public String getUsage() {
+ return USAGE + ":\n\n" + DESC;
+ }
+ }
+
+
+ public class RemoteRegistryDeleteDescriptorCommand extends RemoteRegistryDeleteCommand {
+ static final String USAGE = "delete-descriptor descriptor --registry-client name";
+ static final String DESC = "Deletes a simple descriptor from the specified remote registry.\n";
+
+ public RemoteRegistryDeleteDescriptorCommand(String entryName) {
+ super(entryName);
+ }
+
+ @Override
+ public void execute() throws Exception {
+ execute(DESCRIPTORS__ENTRY + "/" + entryName);
+ }
+
+ @Override
+ public String getUsage() {
+ return USAGE + ":\n\n" + DESC;
+ }
+ }
+
+
private static Properties loadBuildProperties() {
Properties properties = new Properties();
InputStream inputStream = KnoxCLI.class.getClassLoader().getResourceAsStream( "build.properties" );
http://git-wip-us.apache.org/repos/asf/knox/blob/828ea38f/gateway-server/src/test/java/org/apache/hadoop/gateway/service/config/remote/LocalFileSystemRemoteConfigurationRegistryClientService.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/service/config/remote/LocalFileSystemRemoteConfigurationRegistryClientService.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/service/config/remote/LocalFileSystemRemoteConfigurationRegistryClientService.java
new file mode 100644
index 0000000..161c201
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/service/config/remote/LocalFileSystemRemoteConfigurationRegistryClientService.java
@@ -0,0 +1,243 @@
+/**
+ * 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.commons.io.FileUtils;
+import org.apache.hadoop.gateway.config.GatewayConfig;
+import org.apache.hadoop.gateway.service.config.remote.config.RemoteConfigurationRegistriesAccessor;
+import org.apache.hadoop.gateway.services.ServiceLifecycleException;
+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 java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.attribute.PosixFilePermission;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+
+/**
+ * An implementation of RemoteConfigurationRegistryClientService intended to be used for testing without having to
+ * connect to an actual remote configuration registry.
+ */
+public class LocalFileSystemRemoteConfigurationRegistryClientService implements RemoteConfigurationRegistryClientService {
+
+ public static final String TYPE = "LocalFileSystem";
+
+ private Map<String, RemoteConfigurationRegistryClient> clients = new HashMap<>();
+
+
+ @Override
+ public void setAliasService(AliasService aliasService) {
+ // N/A
+ }
+
+ @Override
+ public RemoteConfigurationRegistryClient get(String name) {
+ return clients.get(name);
+ }
+
+ @Override
+ public void init(GatewayConfig config, Map<String, String> options) throws ServiceLifecycleException {
+ List<RemoteConfigurationRegistryConfig> registryConfigurations =
+ RemoteConfigurationRegistriesAccessor.getRemoteRegistryConfigurations(config);
+ for (RemoteConfigurationRegistryConfig registryConfig : registryConfigurations) {
+ if (TYPE.equalsIgnoreCase(registryConfig.getRegistryType())) {
+ RemoteConfigurationRegistryClient registryClient = createClient(registryConfig);
+ clients.put(registryConfig.getName(), registryClient);
+ }
+ }
+ }
+
+ @Override
+ public void start() throws ServiceLifecycleException {
+
+ }
+
+ @Override
+ public void stop() throws ServiceLifecycleException {
+
+ }
+
+
+ private RemoteConfigurationRegistryClient createClient(RemoteConfigurationRegistryConfig config) {
+ String rootDir = config.getConnectionString();
+
+ return new RemoteConfigurationRegistryClient() {
+ private File root = new File(rootDir);
+
+ @Override
+ public String getAddress() {
+ return root.getAbsolutePath();
+ }
+
+ @Override
+ public boolean entryExists(String path) {
+ return (new File(root, path)).exists();
+ }
+
+ @Override
+ public List<EntryACL> getACL(String path) {
+ List<EntryACL> result = new ArrayList<>();
+
+ Path resolved = Paths.get(rootDir, path);
+ try {
+ Map<String, List<String>> collected = new HashMap<>();
+
+ Set<PosixFilePermission> perms = Files.getPosixFilePermissions(resolved);
+ for (PosixFilePermission perm : perms) {
+ String[] parsed = perm.toString().split("_");
+ collected.computeIfAbsent(parsed[0].toLowerCase(), s -> new ArrayList<>()).add(parsed[1].toLowerCase());
+ }
+
+ for (String id : collected.keySet()) {
+ EntryACL acl = new EntryACL() {
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ @Override
+ public String getType() {
+ return "fs";
+ }
+
+ @Override
+ public Object getPermissions() {
+ return collected.get(id).toString();
+ }
+ };
+ result.add(acl);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ @Override
+ public List<String> listChildEntries(String path) {
+ List<String> result = new ArrayList<>();
+
+ File entry = new File(root, path);
+ if (entry.exists() && entry.isDirectory()) {
+ String[] list = entry.list();
+ if (list != null) {
+ result.addAll(Arrays.asList(entry.list()));
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public String getEntryData(String path) {
+ return getEntryData(path, "UTF-8");
+ }
+
+ @Override
+ public String getEntryData(String path, String encoding) {
+ String result = null;
+ File entry = new File(root, path);
+ if (entry.isFile() && entry.exists()) {
+ try {
+ result = FileUtils.readFileToString(entry, encoding);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public void createEntry(String path) {
+ createEntry(path, "");
+ }
+
+ @Override
+ public void createEntry(String path, String data) {
+ createEntry(path, data, "UTF-8");
+ }
+
+ @Override
+ public void createEntry(String path, String data, String encoding) {
+ File entry = new File(root, path);
+ if (!entry.exists()) {
+ if (data != null) {
+ try {
+ FileUtils.writeStringToFile(entry, data, encoding);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ @Override
+ public int setEntryData(String path, String data) {
+ setEntryData(path, data, "UTF-8");
+ return 0;
+ }
+
+ @Override
+ public int setEntryData(String path, String data, String encoding) {
+ File entry = new File(root, path);
+ if (entry.exists()) {
+ try {
+ FileUtils.writeStringToFile(entry, data, encoding);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public void deleteEntry(String path) {
+ File entry = new File(root, path);
+ if (entry.exists()) {
+ entry.delete();
+ }
+ }
+
+ @Override
+ public void addChildEntryListener(String path, ChildEntryListener listener) throws Exception {
+ // N/A
+ }
+
+ @Override
+ public void addEntryListener(String path, EntryListener listener) throws Exception {
+ // N/A
+ }
+
+ @Override
+ public void removeEntryListener(String path) throws Exception {
+ // N/A
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/828ea38f/gateway-server/src/test/java/org/apache/hadoop/gateway/service/config/remote/LocalFileSystemRemoteConfigurationRegistryClientServiceProvider.java
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/java/org/apache/hadoop/gateway/service/config/remote/LocalFileSystemRemoteConfigurationRegistryClientServiceProvider.java b/gateway-server/src/test/java/org/apache/hadoop/gateway/service/config/remote/LocalFileSystemRemoteConfigurationRegistryClientServiceProvider.java
new file mode 100644
index 0000000..42e79c1
--- /dev/null
+++ b/gateway-server/src/test/java/org/apache/hadoop/gateway/service/config/remote/LocalFileSystemRemoteConfigurationRegistryClientServiceProvider.java
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.hadoop.gateway.service.config.remote;
+
+import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegistryClientService;
+
+public class LocalFileSystemRemoteConfigurationRegistryClientServiceProvider implements RemoteConfigurationRegistryClientServiceProvider {
+
+ @Override
+ public String getType() {
+ return LocalFileSystemRemoteConfigurationRegistryClientService.TYPE;
+ }
+
+ @Override
+ public RemoteConfigurationRegistryClientService newInstance() {
+ return new LocalFileSystemRemoteConfigurationRegistryClientService();
+ }
+}
http://git-wip-us.apache.org/repos/asf/knox/blob/828ea38f/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 838f114..2d4586f 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
@@ -27,6 +27,7 @@ import org.apache.hadoop.gateway.services.config.client.RemoteConfigurationRegis
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.apache.hadoop.test.TestUtils;
import org.junit.Before;
import org.junit.Test;
@@ -66,9 +67,11 @@ public class KnoxCLITest {
@Test
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");
+ // Configure a client for the test local filesystem registry implementation
+ config.set("gateway.remote.config.registry.test_client", "type=LocalFileSystem;address=/test");
cli.setConf(config);
// This is only to get the gateway services initialized
@@ -84,6 +87,345 @@ public class KnoxCLITest {
}
@Test
+ public void testListRemoteConfigurationRegistryClients() throws Exception {
+ outContent.reset();
+
+ KnoxCLI cli = new KnoxCLI();
+ String[] args = { "list-registry-clients", "--master","master" };
+
+ Configuration config = new GatewayConfigImpl();
+ cli.setConf(config);
+
+ // Test with no registry clients configured
+ int rc = cli.run(args);
+ assertEquals(0, rc);
+ assertTrue(outContent.toString(), outContent.toString().isEmpty());
+
+ // Test with a single client configured
+ // Configure a client for the test local filesystem registry implementation
+ config.set("gateway.remote.config.registry.test_client", "type=LocalFileSystem;address=/test1");
+ cli.setConf(config);
+ outContent.reset();
+ rc = cli.run(args);
+ assertEquals(0, rc);
+ assertTrue(outContent.toString(), outContent.toString().contains("test_client"));
+
+ // Configure another client for the test local filesystem registry implementation
+ config.set("gateway.remote.config.registry.another_client", "type=LocalFileSystem;address=/test2");
+ cli.setConf(config);
+ outContent.reset();
+ rc = cli.run(args);
+ assertEquals(0, rc);
+ assertTrue(outContent.toString(), outContent.toString().contains("test_client"));
+ assertTrue(outContent.toString(), outContent.toString().contains("another_client"));
+ }
+
+ @Test
+ public void testRemoteConfigurationRegistryGetACLs() throws Exception {
+ outContent.reset();
+
+
+ final File testRoot = TestUtils.createTempDir(this.getClass().getName());
+ try {
+ final File testRegistry = new File(testRoot, "registryRoot");
+
+ final String providerConfigName = "my-provider-config.xml";
+ final String providerConfigContent = "<gateway/>\n";
+ final File testProviderConfig = new File(testRoot, providerConfigName);
+ final String[] uploadArgs = {"upload-provider-config", testProviderConfig.getAbsolutePath(),
+ "--registry-client", "test_client",
+ "--master", "master"};
+ FileUtils.writeStringToFile(testProviderConfig, providerConfigContent);
+
+
+ final String[] args = {"get-registry-acl", "/knox/config/shared-providers",
+ "--registry-client", "test_client",
+ "--master", "master"};
+
+ KnoxCLI cli = new KnoxCLI();
+ Configuration config = new GatewayConfigImpl();
+ // Configure a client for the test local filesystem registry implementation
+ config.set("gateway.remote.config.registry.test_client", "type=LocalFileSystem;address=" + testRegistry);
+ cli.setConf(config);
+
+ int rc = cli.run(uploadArgs);
+ assertEquals(0, rc);
+
+ // Run the test command
+ rc = cli.run(args);
+
+ // Validate the result
+ assertEquals(0, rc);
+ String result = outContent.toString();
+ assertEquals(result, 3, result.split("\n").length);
+ } finally {
+ FileUtils.forceDelete(testRoot);
+ }
+ }
+
+
+ @Test
+ public void testRemoteConfigurationRegistryUploadProviderConfig() throws Exception {
+ outContent.reset();
+
+ final String providerConfigName = "my-provider-config.xml";
+ final String providerConfigContent = "<gateway/>\n";
+
+ final File testRoot = TestUtils.createTempDir(this.getClass().getName());
+ try {
+ final File testRegistry = new File(testRoot, "registryRoot");
+ final File testProviderConfig = new File(testRoot, providerConfigName);
+
+ final String[] args = {"upload-provider-config", testProviderConfig.getAbsolutePath(),
+ "--registry-client", "test_client",
+ "--master", "master"};
+
+ FileUtils.writeStringToFile(testProviderConfig, providerConfigContent);
+
+ KnoxCLI cli = new KnoxCLI();
+ Configuration config = new GatewayConfigImpl();
+ // Configure a client for the test local filesystem registry implementation
+ config.set("gateway.remote.config.registry.test_client", "type=LocalFileSystem;address=" + testRegistry);
+ cli.setConf(config);
+
+ // Run the test command
+ int rc = cli.run(args);
+
+ // Validate the result
+ assertEquals(0, rc);
+ File registryFile = new File(testRegistry, "knox/config/shared-providers/" + providerConfigName);
+ assertTrue(registryFile.exists());
+ assertEquals(FileUtils.readFileToString(registryFile), providerConfigContent);
+ } finally {
+ FileUtils.forceDelete(testRoot);
+ }
+ }
+
+
+ @Test
+ public void testRemoteConfigurationRegistryUploadProviderConfigWithDestinationOverride() throws Exception {
+ outContent.reset();
+
+ final String providerConfigName = "my-provider-config.xml";
+ final String entryName = "my-providers.xml";
+ final String providerConfigContent = "<gateway/>\n";
+
+ final File testRoot = TestUtils.createTempDir(this.getClass().getName());
+ try {
+ final File testRegistry = new File(testRoot, "registryRoot");
+ final File testProviderConfig = new File(testRoot, providerConfigName);
+
+ final String[] args = {"upload-provider-config", testProviderConfig.getAbsolutePath(),
+ "--entry-name", entryName,
+ "--registry-client", "test_client",
+ "--master", "master"};
+
+ FileUtils.writeStringToFile(testProviderConfig, providerConfigContent);
+
+ KnoxCLI cli = new KnoxCLI();
+ Configuration config = new GatewayConfigImpl();
+ // Configure a client for the test local filesystem registry implementation
+ config.set("gateway.remote.config.registry.test_client", "type=LocalFileSystem;address=" + testRegistry);
+ cli.setConf(config);
+
+ // Run the test command
+ int rc = cli.run(args);
+
+ // Validate the result
+ assertEquals(0, rc);
+ assertFalse((new File(testRegistry, "knox/config/shared-providers/" + providerConfigName)).exists());
+ File registryFile = new File(testRegistry, "knox/config/shared-providers/" + entryName);
+ assertTrue(registryFile.exists());
+ assertEquals(FileUtils.readFileToString(registryFile), providerConfigContent);
+ } finally {
+ FileUtils.forceDelete(testRoot);
+ }
+ }
+
+
+ @Test
+ public void testRemoteConfigurationRegistryUploadDescriptor() throws Exception {
+ outContent.reset();
+
+ final String descriptorName = "my-topology.json";
+ final String descriptorContent = testDescriptorContentJSON;
+
+ final File testRoot = TestUtils.createTempDir(this.getClass().getName());
+ try {
+ final File testRegistry = new File(testRoot, "registryRoot");
+ final File testDescriptor = new File(testRoot, descriptorName);
+
+ final String[] args = {"upload-descriptor", testDescriptor.getAbsolutePath(),
+ "--registry-client", "test_client",
+ "--master", "master"};
+
+ FileUtils.writeStringToFile(testDescriptor, descriptorContent);
+
+ KnoxCLI cli = new KnoxCLI();
+ Configuration config = new GatewayConfigImpl();
+ // Configure a client for the test local filesystem registry implementation
+ config.set("gateway.remote.config.registry.test_client", "type=LocalFileSystem;address=" + testRegistry);
+ cli.setConf(config);
+
+ // Run the test command
+ int rc = cli.run(args);
+
+ // Validate the result
+ assertEquals(0, rc);
+ File registryFile = new File(testRegistry, "knox/config/descriptors/" + descriptorName);
+ assertTrue(registryFile.exists());
+ assertEquals(FileUtils.readFileToString(registryFile), descriptorContent);
+ } finally {
+ FileUtils.forceDelete(testRoot);
+ }
+ }
+
+ @Test
+ public void testRemoteConfigurationRegistryUploadDescriptorWithDestinationOverride() throws Exception {
+ outContent.reset();
+
+ final String descriptorName = "my-topology.json";
+ final String entryName = "different-topology.json";
+ final String descriptorContent = testDescriptorContentJSON;
+
+ final File testRoot = TestUtils.createTempDir(this.getClass().getName());
+ try {
+ final File testRegistry = new File(testRoot, "registryRoot");
+ final File testDescriptor = new File(testRoot, descriptorName);
+
+ final String[] args = {"upload-descriptor", testDescriptor.getAbsolutePath(),
+ "--entry-name", entryName,
+ "--registry-client", "test_client",
+ "--master", "master"};
+
+ FileUtils.writeStringToFile(testDescriptor, descriptorContent);
+
+ KnoxCLI cli = new KnoxCLI();
+ Configuration config = new GatewayConfigImpl();
+ // Configure a client for the test local filesystem registry implementation
+ config.set("gateway.remote.config.registry.test_client", "type=LocalFileSystem;address=" + testRegistry);
+ cli.setConf(config);
+
+ // Run the test command
+ int rc = cli.run(args);
+
+ // Validate the result
+ assertEquals(0, rc);
+ assertFalse((new File(testRegistry, "knox/config/descriptors/" + descriptorName)).exists());
+ File registryFile = new File(testRegistry, "knox/config/descriptors/" + entryName);
+ assertTrue(registryFile.exists());
+ assertEquals(FileUtils.readFileToString(registryFile), descriptorContent);
+ } finally {
+ FileUtils.forceDelete(testRoot);
+ }
+ }
+
+ @Test
+ public void testRemoteConfigurationRegistryDeleteProviderConfig() throws Exception {
+ outContent.reset();
+
+ // Create a provider config
+ final String providerConfigName = "my-provider-config.xml";
+ final String providerConfigContent = "<gateway/>\n";
+
+ final File testRoot = TestUtils.createTempDir(this.getClass().getName());
+ try {
+ final File testRegistry = new File(testRoot, "registryRoot");
+ final File testProviderConfig = new File(testRoot, providerConfigName);
+
+ final String[] createArgs = {"upload-provider-config", testProviderConfig.getAbsolutePath(),
+ "--registry-client", "test_client",
+ "--master", "master"};
+
+ FileUtils.writeStringToFile(testProviderConfig, providerConfigContent);
+
+ KnoxCLI cli = new KnoxCLI();
+ Configuration config = new GatewayConfigImpl();
+ // Configure a client for the test local filesystem registry implementation
+ config.set("gateway.remote.config.registry.test_client", "type=LocalFileSystem;address=" + testRegistry);
+ cli.setConf(config);
+
+ // Run the test command
+ int rc = cli.run(createArgs);
+
+ // Validate the result
+ assertEquals(0, rc);
+ File registryFile = new File(testRegistry, "knox/config/shared-providers/" + providerConfigName);
+ assertTrue(registryFile.exists());
+
+ outContent.reset();
+
+ // Delete the created provider config
+ final String[] deleteArgs = {"delete-provider-config", providerConfigName,
+ "--registry-client", "test_client",
+ "--master", "master"};
+ rc = cli.run(deleteArgs);
+ assertEquals(0, rc);
+ assertFalse(registryFile.exists());
+
+ // Try to delete a provider config that does not exist
+ rc = cli.run(new String[]{"delete-provider-config", "imaginary-providers.xml",
+ "--registry-client", "test_client",
+ "--master", "master"});
+ assertEquals(0, rc);
+ } finally {
+ FileUtils.forceDelete(testRoot);
+ }
+ }
+
+ @Test
+ public void testRemoteConfigurationRegistryDeleteDescriptor() throws Exception {
+ outContent.reset();
+
+ final String descriptorName = "my-topology.json";
+ final String descriptorContent = testDescriptorContentJSON;
+
+ final File testRoot = TestUtils.createTempDir(this.getClass().getName());
+ try {
+ final File testRegistry = new File(testRoot, "registryRoot");
+ final File testDescriptor = new File(testRoot, descriptorName);
+
+ final String[] createArgs = {"upload-descriptor", testDescriptor.getAbsolutePath(),
+ "--registry-client", "test_client",
+ "--master", "master"};
+
+ FileUtils.writeStringToFile(testDescriptor, descriptorContent);
+
+ KnoxCLI cli = new KnoxCLI();
+ Configuration config = new GatewayConfigImpl();
+ // Configure a client for the test local filesystem registry implementation
+ config.set("gateway.remote.config.registry.test_client", "type=LocalFileSystem;address=" + testRegistry);
+ cli.setConf(config);
+
+ // Run the test command
+ int rc = cli.run(createArgs);
+
+ // Validate the result
+ assertEquals(0, rc);
+ File registryFile = new File(testRegistry, "knox/config/descriptors/" + descriptorName);
+ assertTrue(registryFile.exists());
+
+ outContent.reset();
+
+ // Delete the created provider config
+ final String[] deleteArgs = {"delete-descriptor", descriptorName,
+ "--registry-client", "test_client",
+ "--master", "master"};
+ rc = cli.run(deleteArgs);
+ assertEquals(0, rc);
+ assertFalse(registryFile.exists());
+
+ // Try to delete a descriptor that does not exist
+ rc = cli.run(new String[]{"delete-descriptor", "bogus.json",
+ "--registry-client", "test_client",
+ "--master", "master"});
+ assertEquals(0, rc);
+ } finally {
+ FileUtils.forceDelete(testRoot);
+ }
+ }
+
+ @Test
public void testSuccessfulAliasLifecycle() throws Exception {
outContent.reset();
String[] args1 = {"create-alias", "alias1", "--value", "testvalue1", "--master", "master"};
@@ -670,4 +1012,21 @@ public class KnoxCLITest {
}
+ private static final String testDescriptorContentJSON = "{\n" +
+ " \"discovery-address\":\"http://localhost:8080\",\n" +
+ " \"discovery-user\":\"maria_dev\",\n" +
+ " \"discovery-pwd-alias\":\"sandbox.discovery.password\",\n" +
+ " \"provider-config-ref\":\"my-provider-config\",\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\":\"HIVE\"},\n" +
+ " {\"name\":\"RESOURCEMANAGER\"}\n" +
+ " ]\n" +
+ "}";
}
http://git-wip-us.apache.org/repos/asf/knox/blob/828ea38f/gateway-server/src/test/resources/META-INF/services/org.apache.hadoop.gateway.service.config.remote.RemoteConfigurationRegistryClientServiceProvider
----------------------------------------------------------------------
diff --git a/gateway-server/src/test/resources/META-INF/services/org.apache.hadoop.gateway.service.config.remote.RemoteConfigurationRegistryClientServiceProvider b/gateway-server/src/test/resources/META-INF/services/org.apache.hadoop.gateway.service.config.remote.RemoteConfigurationRegistryClientServiceProvider
new file mode 100644
index 0000000..ffd9284
--- /dev/null
+++ b/gateway-server/src/test/resources/META-INF/services/org.apache.hadoop.gateway.service.config.remote.RemoteConfigurationRegistryClientServiceProvider
@@ -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.service.config.remote.LocalFileSystemRemoteConfigurationRegistryClientServiceProvider