This is an automated email from the ASF dual-hosted git repository.
amagyar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git
The following commit(s) were added to refs/heads/master by this push:
new bb5d265d8 KNOX-3002 - KnoxCLI command for generating descriptor for a
role type from a list of hosts (#835)
bb5d265d8 is described below
commit bb5d265d861489925f158faff761090d672205db
Author: Attila Magyar <[email protected]>
AuthorDate: Mon Feb 26 10:37:00 2024 +0100
KNOX-3002 - KnoxCLI command for generating descriptor for a role type from
a list of hosts (#835)
---
.../knox/gateway/util/DescriptorGenerator.java | 84 ++++++++++++++++++++
.../java/org/apache/knox/gateway/util/KnoxCLI.java | 91 +++++++++++++++++++++-
.../org/apache/knox/gateway/util/ServiceUrls.java | 57 ++++++++++++++
.../knox/gateway/util/DescriptorGeneratorTest.java | 81 +++++++++++++++++++
4 files changed, 309 insertions(+), 4 deletions(-)
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/util/DescriptorGenerator.java
b/gateway-server/src/main/java/org/apache/knox/gateway/util/DescriptorGenerator.java
new file mode 100644
index 000000000..5f31f11b2
--- /dev/null
+++
b/gateway-server/src/main/java/org/apache/knox/gateway/util/DescriptorGenerator.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.knox.gateway.model.DescriptorConfiguration;
+import org.apache.knox.gateway.model.Topology;
+
+public class DescriptorGenerator {
+ private static final ObjectMapper mapper = new ObjectMapper();
+ private final String descriptorName;
+ private final String providerName;
+ private final String serviceName;
+ private final ServiceUrls serviceUrls;
+ private final Map<String, String> params;
+
+ static {
+ /* skip printing out null fields */
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+ }
+
+ public DescriptorGenerator(String descriptorName, String providerName,
String serviceName, ServiceUrls serviceUrls, Map<String, String> params) {
+ this.descriptorName = descriptorName;
+ this.providerName = providerName;
+ this.serviceName = serviceName.toUpperCase(Locale.ROOT);
+ this.serviceUrls = serviceUrls;
+ this.params = params;
+ }
+
+ public void saveDescriptor(File outputDir, boolean forceOverwrite) {
+ File outputFile = new File(outputDir, descriptorName);
+ if (outputFile.exists() && !forceOverwrite) {
+ throw new IllegalArgumentException(outputFile + " already exists");
+ }
+ DescriptorConfiguration descriptor = new DescriptorConfiguration();
+ descriptor.setName(FilenameUtils.removeExtension(descriptorName));
+ descriptor.setProviderConfig(FilenameUtils.removeExtension(providerName));
+ Topology.Service service = new Topology.Service();
+ service.setRole(serviceName);
+ service.setUrls(serviceUrls.toList());
+ setParams(service, params);
+ descriptor.setServices(Arrays.asList(service));
+ try {
+ mapper.writerWithDefaultPrettyPrinter()
+ .writeValue(outputFile, descriptor);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ private void setParams(Topology.Service service, Map<String, String> params)
{
+ List<Topology.Param> paramList = new ArrayList<>();
+ for (Map.Entry<String, String> each : params.entrySet()) {
+ paramList.add(new Topology.Param(each.getKey(), each.getValue()));
+ }
+ service.setParams(paramList);
+ }
+}
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
b/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
index 71fde73fa..4ce440f4a 100644
--- a/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/util/KnoxCLI.java
@@ -43,6 +43,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
+import java.util.TreeMap;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -134,6 +135,7 @@ public class KnoxCLI extends Configured implements Tool {
" [" + RemoteRegistryGetACLCommand.USAGE + "]\n" +
" [" + TopologyConverter.USAGE + "]\n" +
" [" + JWKGenerator.USAGE + "]\n" +
+ " [" + GenerateDescriptorCommand.USAGE + "]\n" +
" [" + TokenMigration.USAGE + "]\n";
/** allows stdout to be captured if necessary */
@@ -173,6 +175,9 @@ public class KnoxCLI extends Configured implements Tool {
private String discoveryUser;
private String discoveryPasswordAlias;
private String discoveryType;
+ private String serviceName;
+ private String urlsFilePath;
+ private final Map<String, String> params = new TreeMap<>();
// For testing only
private String master;
@@ -388,11 +393,23 @@ public class KnoxCLI extends Configured implements Tool {
}
this.topologyName = args[++i];
} else if (args[i].equals("--descriptor-name")) {
- if( i+1 >= args.length || args[i+1].startsWith( "-" ) ) {
+ if (i + 1 >= args.length || args[i + 1].startsWith("-")) {
printKnoxShellUsage();
return -1;
}
this.descriptorName = args[++i];
+ } else if (args[i].equals("--service-name")) {
+ if (i + 1 >= args.length || args[i + 1].startsWith("-")) {
+ printKnoxShellUsage();
+ return -1;
+ }
+ this.serviceName = args[++i];
+ } else if (args[i].equals("--service-urls-file")) {
+ if (i + 1 >= args.length || args[i + 1].startsWith("-")) {
+ printKnoxShellUsage();
+ return -1;
+ }
+ this.urlsFilePath = args[++i];
} else if (args[i].equals("--output-dir")) {
if( i+1 >= args.length || args[i+1].startsWith( "-" ) ) {
printKnoxShellUsage();
@@ -519,8 +536,21 @@ public class KnoxCLI extends Configured implements Tool {
} else if (args[i].equalsIgnoreCase("convert-topology")) {
if (args.length >= 5) {
command = new TopologyConverter();
+ } else {
+ printKnoxShellUsage();
+ return -1;
}
- else {
+ } else if (args[i].equalsIgnoreCase("generate-descriptor")) {
+ if (args.length >= 7) {
+ command = new GenerateDescriptorCommand();
+ } else {
+ printKnoxShellUsage();
+ return -1;
+ }
+ } else if (args[i].equalsIgnoreCase("--param")) {
+ if (i + 2 < args.length) {
+ params.put(args[++i], args[++i]);
+ } else {
printKnoxShellUsage();
return -1;
}
@@ -2315,7 +2345,7 @@ public class KnoxCLI extends Configured implements Tool {
public static final String USAGE =
"convert-topology --path \"path/to/topology.xml\" --provider-name
my-provider.json [--descriptor-name my-descriptor.json] "
- + "[--topology-name topologyName] [--output-path
\"path/to/configs/\"] [--force] [--cluster clusterName] [--discovery-url url] "
+ + "[--topology-name topologyName] [--output-dir
\"path/to/configs/\"] [--force] [--cluster clusterName] [--discovery-url url] "
+ "[--discovery-user discoveryUser] [--discovery-pwd-alias
discoveryPasswordAlias] [--discovery-type discoveryType]";
public static final String DESC =
"Convert Knox topology file to provider and descriptor config files \n"
@@ -2325,7 +2355,7 @@ public class KnoxCLI extends Configured implements Tool {
+ "--descriptor-name (optional) name of descriptor json config
file (including .json extension) \n"
+ "--topology-name (optional) topology-name can be use instead of
--path option, if used, KnoxCLI will attempt to find topology from deployed
topologies.\n"
+ "\t if not provided topology name will be used as descriptor
name \n"
- + "--output-dir (optional) output directory to save provider and
descriptor config files \n"
+ + "--output-dir (optional) output directory to save provider and
descriptor config files. Default is the current working directory. \n"
+ "\t if not provided config files will be saved in appropriate
Knox config directory \n"
+ "--force (optional) force rewriting of existing files, if not
used, command will fail when the configs files with same name already exist. \n"
+ "--cluster (optional) cluster name, required for service
discovery \n"
@@ -2409,6 +2439,59 @@ public class KnoxCLI extends Configured implements Tool {
}
+ public class GenerateDescriptorCommand extends Command {
+
+ public static final String USAGE =
+ "generate-descriptor --service-urls-file \"path/to/urls.txt\"
--service-name SERVICE_NAME \n" +
+ "--provider-name my-provider.json --descriptor-name
my-descriptor.json \n" +
+ "[--output-dir /path/to/output_dir] \n" +
+ "[--param key1 value1] \n" +
+ "[--param key2 value2] \n" +
+ "[--force] \n";
+ public static final String DESC =
+ "Create Knox topology descriptor file for one service\n"
+ + "Options are as follows: \n"
+ + "--service-urls-file (required) path to a text file
containing service urls \n"
+ + "--service-name (required) the name of the service, such
as WEBHDFS, IMPALAUI or HIVE \n"
+ + "--descriptor-name (required) name of descriptor to be
created \n"
+ + "--provider-name (required) name of the referenced
shared provider \n"
+ + "--output-dir (optional) output directory to save the
descriptor file \n"
+ + "--param (optional) service param name and value \n"
+ + "--force (optional) force rewriting of existing files,
if not used, command will fail when the configs files with same name already
exist. \n";
+
+ @Override
+ public void execute() throws Exception {
+ validateParams();
+ File output = StringUtils.isBlank(outputDir) ? new File(".") : new
File(outputDir);
+ DescriptorGenerator generator =
+ new DescriptorGenerator(descriptorName, providerName,
serviceName, ServiceUrls.fromFile(urlsFilePath), params);
+ generator.saveDescriptor(output, force);
+ out.println("Descriptor " + descriptorName + " was successfully saved to
" + output.getAbsolutePath() + "\n");
+ }
+
+ private void validateParams() {
+ if (StringUtils.isBlank(FilenameUtils.getExtension(providerName))
+ ||
StringUtils.isBlank(FilenameUtils.getExtension(descriptorName))) {
+ throw new IllegalArgumentException("JSON extension is required for
provider and descriptor file names");
+ }
+ if (StringUtils.isBlank(urlsFilePath) ) {
+ throw new IllegalArgumentException("Missing --service-urls-file");
+ }
+ if (!new File(urlsFilePath).isFile()) {
+ throw new IllegalArgumentException(urlsFilePath + " does not exist");
+ }
+ if (StringUtils.isBlank(serviceName)) {
+ throw new IllegalArgumentException("Missing --service-name");
+ }
+ }
+
+ @Override
+ public String getUsage() {
+ return USAGE + ":\n\n" + DESC;
+ }
+
+ }
+
public class JWKGenerator extends Command {
public static final String USAGE = "generate-jwk [--jwkAlg
HS256|HS384|HS512] [--saveAlias alias] [--topology topology]";
diff --git
a/gateway-server/src/main/java/org/apache/knox/gateway/util/ServiceUrls.java
b/gateway-server/src/main/java/org/apache/knox/gateway/util/ServiceUrls.java
new file mode 100644
index 000000000..3f244698a
--- /dev/null
+++ b/gateway-server/src/main/java/org/apache/knox/gateway/util/ServiceUrls.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+
+public class ServiceUrls {
+ private final List<String> urls;
+
+ public static ServiceUrls fromFile(String urlsFilePath) {
+ return fromFile(new File(urlsFilePath));
+ }
+
+ public static ServiceUrls fromFile(File urlsFilePath) {
+ try {
+ List<String> lines = FileUtils.readLines(urlsFilePath,
Charset.defaultCharset()).stream()
+ .map(String::trim)
+ .filter(StringUtils::isNotBlank)
+ .collect(Collectors.toList());
+ return new ServiceUrls(lines);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public ServiceUrls(List<String> urls) {
+ this.urls = urls;
+ }
+
+ public List<String> toList() {
+ return Collections.unmodifiableList(urls);
+ }
+}
diff --git
a/gateway-server/src/test/java/org/apache/knox/gateway/util/DescriptorGeneratorTest.java
b/gateway-server/src/test/java/org/apache/knox/gateway/util/DescriptorGeneratorTest.java
new file mode 100644
index 000000000..8beaf938f
--- /dev/null
+++
b/gateway-server/src/test/java/org/apache/knox/gateway/util/DescriptorGeneratorTest.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.knox.gateway.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.knox.gateway.model.DescriptorConfiguration;
+import org.apache.knox.gateway.model.Topology;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+public class DescriptorGeneratorTest {
+ private static final ObjectMapper mapper = new ObjectMapper();
+ private static final String TEST_DESC_1 = "test_desc1.json";
+ private static final String TEST_PROV_1 = "test_prov1.json";
+ private static final String IMPALA_UI = "IMPALAUI";
+ private static final List<String> URLS =
+ Arrays.asList("http://amagyar-1.test.site:25000/",
"http://amagyar-2.test.site:25000");
+
+ private static final Map<String,String> PARAMS = new HashMap<>();
+ static { PARAMS.put("KEY_1", "VAL_1"); }
+
+ @Rule
+ public TemporaryFolder folder= new TemporaryFolder();
+
+ @Test
+ public void testCreateDescriptor() throws Exception {
+ DescriptorGenerator generator = new DescriptorGenerator(TEST_DESC_1,
TEST_PROV_1, IMPALA_UI, new ServiceUrls(URLS), PARAMS);
+ File outputDir = folder.newFolder().getAbsoluteFile();
+ File outputFile = new File(outputDir, TEST_DESC_1);
+ generator.saveDescriptor(outputDir, false);
+ System.out.println(FileUtils.readFileToString(outputFile,
Charset.defaultCharset()));
+ DescriptorConfiguration result = mapper
+ .readerFor(DescriptorConfiguration.class)
+ .readValue(outputFile);
+ assertEquals(FilenameUtils.removeExtension(TEST_PROV_1),
result.getProviderConfig());
+ assertEquals(FilenameUtils.removeExtension(TEST_DESC_1), result.getName());
+ assertEquals(1, result.getServices().size());
+ Topology.Service service = result.getServices().get(0);
+ assertEquals(IMPALA_UI, service.getRole());
+ assertEquals(URLS, service.getUrls());
+ assertEquals(1, service.getParams().size());
+ assertEquals("KEY_1", service.getParams().get(0).getName());
+ assertEquals("VAL_1", service.getParams().get(0).getValue());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testOutputAlreadyExists() throws Exception {
+ DescriptorGenerator generator = new DescriptorGenerator(TEST_DESC_1,
TEST_PROV_1, IMPALA_UI, new ServiceUrls(URLS), PARAMS);
+ File outputDir = folder.newFolder().getAbsoluteFile();
+ File outputFile = new File(outputDir, TEST_DESC_1);
+ outputFile.createNewFile();
+ generator.saveDescriptor(outputDir, false);
+ }
+}
\ No newline at end of file