HDDS-455. Ozone genconf tool must use picocli. Contributed by Dinesh Chitlangia.
This commit is contained in:
parent
19ad5be651
commit
35c7351f4b
|
@ -53,7 +53,7 @@ following command. This will generate a template called ```ozone-site.xml``` at
|
||||||
the specified path (directory).
|
the specified path (directory).
|
||||||
|
|
||||||
{{< highlight bash >}}
|
{{< highlight bash >}}
|
||||||
ozone genconf -output <path>
|
ozone genconf <path>
|
||||||
{{< /highlight >}}
|
{{< /highlight >}}
|
||||||
|
|
||||||
Let us look at the settings inside the generated file (ozone-site.xml) and
|
Let us look at the settings inside the generated file (ozone-site.xml) and
|
||||||
|
|
|
@ -18,7 +18,12 @@
|
||||||
|
|
||||||
package org.apache.hadoop.ozone.genconf;
|
package org.apache.hadoop.ozone.genconf;
|
||||||
|
|
||||||
|
import org.apache.hadoop.hdds.cli.GenericCli;
|
||||||
|
import org.apache.hadoop.hdds.cli.HddsVersionProvider;
|
||||||
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
|
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
|
||||||
|
import picocli.CommandLine.Command;
|
||||||
|
import picocli.CommandLine.Parameters;
|
||||||
|
import picocli.CommandLine.PicocliException;
|
||||||
|
|
||||||
import javax.xml.bind.JAXBContext;
|
import javax.xml.bind.JAXBContext;
|
||||||
import javax.xml.bind.JAXBException;
|
import javax.xml.bind.JAXBException;
|
||||||
|
@ -30,112 +35,58 @@ import java.nio.file.InvalidPathException;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GenerateOzoneRequiredConfigurations - A tool to generate ozone-site.xml<br>
|
* GenerateOzoneRequiredConfigurations - A tool to generate ozone-site.xml<br>
|
||||||
* This tool generates an ozone-site.xml with minimally required configs.
|
* This tool generates an ozone-site.xml with minimally required configs.
|
||||||
* This tool can be invoked as follows:<br>
|
* This tool can be invoked as follows:<br>
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>ozone genconf -output <Path to output file></li>
|
* <li>ozone genconf <Path to output file></li>
|
||||||
* <li>ozone genconf -help</li>
|
* <li>ozone genconf --help</li>
|
||||||
|
* <li>ozone genconf -h</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public final class GenerateOzoneRequiredConfigurations {
|
@Command(
|
||||||
|
name = "ozone genconf",
|
||||||
|
description = "Tool to generate template ozone-site.xml",
|
||||||
|
versionProvider = HddsVersionProvider.class,
|
||||||
|
mixinStandardHelpOptions = true)
|
||||||
|
public final class GenerateOzoneRequiredConfigurations extends GenericCli {
|
||||||
|
|
||||||
private static final String OUTPUT = "-output";
|
@Parameters(arity = "1..1",
|
||||||
private static final String HELP = "-help";
|
description = "Directory path where ozone-site file should be generated.")
|
||||||
private static final String USAGE = "Usage: \nozone genconf "
|
private String path;
|
||||||
+ OUTPUT + " <Path to output file> \n"
|
|
||||||
+ "ozone genconf "
|
|
||||||
+ HELP;
|
|
||||||
private static final int SUCCESS = 0;
|
|
||||||
private static final int FAILURE = 1;
|
|
||||||
|
|
||||||
private GenerateOzoneRequiredConfigurations() {
|
|
||||||
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Entry point for using genconf tool.
|
* Entry point for using genconf tool.
|
||||||
*
|
*
|
||||||
* @param args
|
* @param args
|
||||||
* @throws JAXBException
|
*
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) throws Exception {
|
||||||
|
new GenerateOzoneRequiredConfigurations().run(args);
|
||||||
try {
|
|
||||||
if (args.length == 0) {
|
|
||||||
System.out.println(USAGE);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (args[0]) {
|
|
||||||
case OUTPUT:
|
|
||||||
if (args.length > 1) {
|
|
||||||
int result = generateConfigurations(args[1]);
|
|
||||||
} else {
|
|
||||||
System.out.println("Path to output file is mandatory");
|
|
||||||
System.out.println(USAGE);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case HELP:
|
|
||||||
System.out.println(USAGE);
|
|
||||||
System.exit(0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
System.out.println(USAGE);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Check if the path is valid directory.
|
public Void call() throws Exception {
|
||||||
*
|
generateConfigurations(path);
|
||||||
* @param path
|
return null;
|
||||||
* @return true, if path is valid directory, else return false
|
|
||||||
*/
|
|
||||||
public static boolean isValidPath(String path) {
|
|
||||||
try {
|
|
||||||
return Files.isDirectory(Paths.get(path));
|
|
||||||
} catch (InvalidPathException | NullPointerException ex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if user has permission to write in the specified path.
|
|
||||||
*
|
|
||||||
* @param path
|
|
||||||
* @return true, if the user has permission to write, else returns false
|
|
||||||
*/
|
|
||||||
public static boolean canWrite(String path) {
|
|
||||||
File file = new File(path);
|
|
||||||
return file.canWrite();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate ozone-site.xml at specified path.
|
* Generate ozone-site.xml at specified path.
|
||||||
*
|
|
||||||
* @param path
|
* @param path
|
||||||
* @return SUCCESS(0) if file can be generated, else returns FAILURE(1)
|
* @throws PicocliException
|
||||||
* @throws JAXBException
|
* @throws JAXBException
|
||||||
*/
|
*/
|
||||||
public static int generateConfigurations(String path) throws JAXBException {
|
public static void generateConfigurations(String path) throws
|
||||||
|
PicocliException, JAXBException {
|
||||||
|
|
||||||
if (!isValidPath(path)) {
|
if (!isValidPath(path)) {
|
||||||
System.out.println("Invalid directory path.");
|
throw new PicocliException("Invalid directory path.");
|
||||||
return FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!canWrite(path)) {
|
if (!canWrite(path)) {
|
||||||
System.out.println("Insufficient permission.");
|
throw new PicocliException("Insufficient permission.");
|
||||||
return FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OzoneConfiguration oc = new OzoneConfiguration();
|
OzoneConfiguration oc = new OzoneConfiguration();
|
||||||
|
@ -168,7 +119,30 @@ public final class GenerateOzoneRequiredConfigurations {
|
||||||
m.marshal(requiredConfig, new File(path, "ozone-site.xml"));
|
m.marshal(requiredConfig, new File(path, "ozone-site.xml"));
|
||||||
|
|
||||||
System.out.println("ozone-site.xml has been generated at " + path);
|
System.out.println("ozone-site.xml has been generated at " + path);
|
||||||
|
}
|
||||||
|
|
||||||
return SUCCESS;
|
/**
|
||||||
|
* Check if the path is valid directory.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* @return true, if path is valid directory, else return false
|
||||||
|
*/
|
||||||
|
public static boolean isValidPath(String path) {
|
||||||
|
try {
|
||||||
|
return Files.isDirectory(Paths.get(path));
|
||||||
|
} catch (InvalidPathException | NullPointerException ex) {
|
||||||
|
return Boolean.FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if user has permission to write in the specified path.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* @return true, if the user has permission to write, else returns false
|
||||||
|
*/
|
||||||
|
public static boolean canWrite(String path) {
|
||||||
|
File file = new File(path);
|
||||||
|
return file.canWrite();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,23 +21,40 @@ package org.apache.hadoop.ozone.genconf;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.commons.lang3.RandomStringUtils;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
import org.apache.hadoop.test.GenericTestUtils;
|
import org.apache.hadoop.test.GenericTestUtils;
|
||||||
import org.hamcrest.CoreMatchers;
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import picocli.CommandLine;
|
||||||
|
import picocli.CommandLine.ExecutionException;
|
||||||
|
import picocli.CommandLine.IExceptionHandler2;
|
||||||
|
import picocli.CommandLine.ParseResult;
|
||||||
|
import picocli.CommandLine.ParameterException;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests GenerateOzoneRequiredConfigurations.
|
* Tests GenerateOzoneRequiredConfigurations.
|
||||||
*/
|
*/
|
||||||
public class TestGenerateOzoneRequiredConfigurations {
|
public class TestGenerateOzoneRequiredConfigurations {
|
||||||
private static File outputBaseDir;
|
private static File outputBaseDir;
|
||||||
|
private static GenerateOzoneRequiredConfigurations genconfTool;
|
||||||
|
private static final Logger LOG =
|
||||||
|
LoggerFactory.getLogger(TestGenerateOzoneRequiredConfigurations.class);
|
||||||
|
private final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
private final ByteArrayOutputStream err = new ByteArrayOutputStream();
|
||||||
|
private static final PrintStream OLD_OUT = System.out;
|
||||||
|
private static final PrintStream OLD_ERR = System.err;
|
||||||
/**
|
/**
|
||||||
* Creates output directory which will be used by the test-cases.
|
* Creates output directory which will be used by the test-cases.
|
||||||
* If a test-case needs a separate directory, it has to create a random
|
* If a test-case needs a separate directory, it has to create a random
|
||||||
|
@ -49,6 +66,24 @@ public class TestGenerateOzoneRequiredConfigurations {
|
||||||
public static void init() throws Exception {
|
public static void init() throws Exception {
|
||||||
outputBaseDir = GenericTestUtils.getTestDir();
|
outputBaseDir = GenericTestUtils.getTestDir();
|
||||||
FileUtils.forceMkdir(outputBaseDir);
|
FileUtils.forceMkdir(outputBaseDir);
|
||||||
|
genconfTool = new GenerateOzoneRequiredConfigurations();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws Exception {
|
||||||
|
System.setOut(new PrintStream(out));
|
||||||
|
System.setErr(new PrintStream(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void reset() {
|
||||||
|
// reset stream after each unit test
|
||||||
|
out.reset();
|
||||||
|
err.reset();
|
||||||
|
|
||||||
|
// restore system streams
|
||||||
|
System.setOut(OLD_OUT);
|
||||||
|
System.setErr(OLD_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,6 +94,57 @@ public class TestGenerateOzoneRequiredConfigurations {
|
||||||
FileUtils.deleteDirectory(outputBaseDir);
|
FileUtils.deleteDirectory(outputBaseDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void execute(String[] args, String msg) {
|
||||||
|
List<String> arguments = new ArrayList(Arrays.asList(args));
|
||||||
|
LOG.info("Executing shell command with args {}", arguments);
|
||||||
|
CommandLine cmd = genconfTool.getCmd();
|
||||||
|
|
||||||
|
IExceptionHandler2<List<Object>> exceptionHandler =
|
||||||
|
new IExceptionHandler2<List<Object>>() {
|
||||||
|
@Override
|
||||||
|
public List<Object> handleParseException(ParameterException ex,
|
||||||
|
String[] args) {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Object> handleExecutionException(ExecutionException ex,
|
||||||
|
ParseResult parseResult) {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cmd.parseWithHandlers(new CommandLine.RunLast(),
|
||||||
|
exceptionHandler, args);
|
||||||
|
Assert.assertTrue(out.toString().contains(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeWithException(String[] args, String msg) {
|
||||||
|
List<String> arguments = new ArrayList(Arrays.asList(args));
|
||||||
|
LOG.info("Executing shell command with args {}", arguments);
|
||||||
|
CommandLine cmd = genconfTool.getCmd();
|
||||||
|
|
||||||
|
IExceptionHandler2<List<Object>> exceptionHandler =
|
||||||
|
new IExceptionHandler2<List<Object>>() {
|
||||||
|
@Override
|
||||||
|
public List<Object> handleParseException(ParameterException ex,
|
||||||
|
String[] args) {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Object> handleExecutionException(ExecutionException ex,
|
||||||
|
ParseResult parseResult) {
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try{
|
||||||
|
cmd.parseWithHandlers(new CommandLine.RunLast(),
|
||||||
|
exceptionHandler, args);
|
||||||
|
}catch(Exception ex){
|
||||||
|
Assert.assertTrue(ex.getMessage().contains(msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests a valid path and generates ozone-site.xml by calling
|
* Tests a valid path and generates ozone-site.xml by calling
|
||||||
* {@code GenerateOzoneRequiredConfigurations#generateConfigurations}.
|
* {@code GenerateOzoneRequiredConfigurations#generateConfigurations}.
|
||||||
|
@ -68,79 +154,54 @@ public class TestGenerateOzoneRequiredConfigurations {
|
||||||
@Test
|
@Test
|
||||||
public void testGenerateConfigurations() throws Exception {
|
public void testGenerateConfigurations() throws Exception {
|
||||||
File tempPath = getRandomTempDir();
|
File tempPath = getRandomTempDir();
|
||||||
String[] args = new String[]{"-output", tempPath.getAbsolutePath()};
|
String[] args = new String[]{tempPath.getAbsolutePath()};
|
||||||
|
execute(args, "ozone-site.xml has been generated at " +
|
||||||
Assert.assertEquals("Path is valid",
|
tempPath.getAbsolutePath());
|
||||||
true, GenerateOzoneRequiredConfigurations.isValidPath(args[1]));
|
|
||||||
|
|
||||||
Assert.assertEquals("Permission is valid",
|
|
||||||
true, GenerateOzoneRequiredConfigurations.canWrite(args[1]));
|
|
||||||
|
|
||||||
Assert.assertEquals("Config file generated",
|
|
||||||
0, GenerateOzoneRequiredConfigurations.generateConfigurations(args[1]));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests ozone-site.xml generation by calling
|
* Test to avoid generating ozone-site.xml when insufficient permission.
|
||||||
* {@code GenerateOzoneRequiredConfigurations#main}.
|
|
||||||
*
|
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGenerateConfigurationsThroughMainMethod() throws Exception {
|
public void genconfFailureByInsufficientPermissions() throws Exception {
|
||||||
File tempPath = getRandomTempDir();
|
|
||||||
String[] args = new String[]{"-output", tempPath.getAbsolutePath()};
|
|
||||||
ByteArrayOutputStream outContent = new ByteArrayOutputStream();
|
|
||||||
PrintStream oldStream = System.out;
|
|
||||||
try (PrintStream ps = new PrintStream(outContent)) {
|
|
||||||
System.setOut(ps);
|
|
||||||
GenerateOzoneRequiredConfigurations.main(args);
|
|
||||||
Assert.assertThat(outContent.toString(), CoreMatchers.containsString(
|
|
||||||
"ozone-site.xml has been generated at"));
|
|
||||||
System.setOut(oldStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test to avoid generating ozone-site.xml when invalid permission.
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void generateConfigurationsFailure() throws Exception {
|
|
||||||
File tempPath = getRandomTempDir();
|
File tempPath = getRandomTempDir();
|
||||||
tempPath.setReadOnly();
|
tempPath.setReadOnly();
|
||||||
String[] args = new String[]{"-output", tempPath.getAbsolutePath()};
|
String[] args = new String[]{tempPath.getAbsolutePath()};
|
||||||
GenerateOzoneRequiredConfigurations.main(args);
|
executeWithException(args, "Insufficient permission.");
|
||||||
|
|
||||||
Assert.assertEquals("Path is valid",
|
|
||||||
true, GenerateOzoneRequiredConfigurations.isValidPath(args[1]));
|
|
||||||
|
|
||||||
Assert.assertEquals("Invalid permission",
|
|
||||||
false, GenerateOzoneRequiredConfigurations.canWrite(args[1]));
|
|
||||||
|
|
||||||
Assert.assertEquals("Config file not generated",
|
|
||||||
1, GenerateOzoneRequiredConfigurations.generateConfigurations(args[1]));
|
|
||||||
tempPath.setWritable(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test to avoid generating ozone-site.xml when invalid permission.
|
* Test to avoid generating ozone-site.xml when invalid path.
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void generateConfigurationsFailureForInvalidPath() throws Exception {
|
public void genconfFailureByInvalidPath() throws Exception {
|
||||||
File tempPath = getRandomTempDir();
|
File tempPath = getRandomTempDir();
|
||||||
tempPath.setReadOnly();
|
String[] args = new String[]{"invalid-path"};
|
||||||
String[] args = new String[]{"-output",
|
executeWithException(args, "Invalid directory path.");
|
||||||
tempPath.getAbsolutePath() + "/ozone-site.xml"};
|
}
|
||||||
GenerateOzoneRequiredConfigurations.main(args);
|
|
||||||
|
|
||||||
Assert.assertEquals("Path is invalid", false,
|
/**
|
||||||
GenerateOzoneRequiredConfigurations.isValidPath(args[1]));
|
* Test to avoid generating ozone-site.xml when path not specified.
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void genconfPathNotSpecified() throws Exception {
|
||||||
|
File tempPath = getRandomTempDir();
|
||||||
|
String[] args = new String[]{};
|
||||||
|
executeWithException(args, "Missing required parameter: <path>");
|
||||||
|
}
|
||||||
|
|
||||||
Assert.assertEquals("Config file not generated", 1,
|
/**
|
||||||
GenerateOzoneRequiredConfigurations.generateConfigurations(args[1]));
|
* Test to check help message.
|
||||||
tempPath.setWritable(true);
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void genconfHelp() throws Exception {
|
||||||
|
File tempPath = getRandomTempDir();
|
||||||
|
String[] args = new String[]{"--help"};
|
||||||
|
execute(args, "Usage: ozone genconf [-hV] [--verbose]");
|
||||||
}
|
}
|
||||||
|
|
||||||
private File getRandomTempDir() throws IOException {
|
private File getRandomTempDir() throws IOException {
|
||||||
|
|
Loading…
Reference in New Issue