Format projects under :distribution:tools (#51292)

Backport of #51226. Opt-in the sub-projects of :distribution:tools for
automatic formatting.
This commit is contained in:
Rory Hunter 2020-01-22 11:19:17 +00:00 committed by GitHub
parent 421aa14972
commit 1009f92b03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 834 additions and 602 deletions

View File

@ -107,6 +107,9 @@ subprojects {
// switched to an exclude list, and eventualy removed completely. // switched to an exclude list, and eventualy removed completely.
def projectPathsToFormat = [ def projectPathsToFormat = [
':build-tools', ':build-tools',
':distribution:tools:java-version-checker',
':distribution:tools:launchers',
':distribution:tools:plugin-cli',
':x-pack:plugin:autoscaling', ':x-pack:plugin:autoscaling',
':x-pack:plugin:enrich' ':x-pack:plugin:enrich'
] ]

View File

@ -27,8 +27,7 @@ import java.util.Locale;
*/ */
final class JavaVersionChecker { final class JavaVersionChecker {
private JavaVersionChecker() { private JavaVersionChecker() {}
}
/** /**
* The main entry point. The exit code is 0 if the Java version is at least 1.8, otherwise the exit code is 1. * The main entry point. The exit code is 0 if the Java version is at least 1.8, otherwise the exit code is 1.
@ -44,7 +43,8 @@ final class JavaVersionChecker {
final String message = String.format( final String message = String.format(
Locale.ROOT, Locale.ROOT,
"the minimum required Java version is 8; your Java version from [%s] does not meet this requirement", "the minimum required Java version is 8; your Java version from [%s] does not meet this requirement",
System.getProperty("java.home")); System.getProperty("java.home")
);
errPrintln(message); errPrintln(message);
exit(1); exit(1);
} }
@ -52,7 +52,8 @@ final class JavaVersionChecker {
final String message = String.format( final String message = String.format(
Locale.ROOT, Locale.ROOT,
"future versions of Elasticsearch will require Java 11; your Java version from [%s] does not meet this requirement", "future versions of Elasticsearch will require Java 11; your Java version from [%s] does not meet this requirement",
System.getProperty("java.home")); System.getProperty("java.home")
);
errPrintln(message); errPrintln(message);
} }
exit(0); exit(0);

View File

@ -78,14 +78,18 @@ final class JvmErgonomics {
return ergonomicChoices; return ergonomicChoices;
} }
private static final Pattern OPTION = private static final Pattern OPTION = Pattern.compile(
Pattern.compile("^\\s*\\S+\\s+(?<flag>\\S+)\\s+:?=\\s+(?<value>\\S+)?\\s+\\{[^}]+?\\}(\\s+\\{[^}]+})?"); "^\\s*\\S+\\s+(?<flag>\\S+)\\s+:?=\\s+(?<value>\\S+)?\\s+\\{[^}]+?\\}(\\s+\\{[^}]+})?"
);
static Map<String, Optional<String>> finalJvmOptions( static Map<String, Optional<String>> finalJvmOptions(final List<String> userDefinedJvmOptions) throws InterruptedException,
final List<String> userDefinedJvmOptions) throws InterruptedException, IOException { IOException {
return Collections.unmodifiableMap(flagsFinal(userDefinedJvmOptions).stream() return Collections.unmodifiableMap(
.map(OPTION::matcher).filter(Matcher::matches) flagsFinal(userDefinedJvmOptions).stream()
.collect(Collectors.toMap(m -> m.group("flag"), m -> Optional.ofNullable(m.group("value"))))); .map(OPTION::matcher)
.filter(Matcher::matches)
.collect(Collectors.toMap(m -> m.group("flag"), m -> Optional.ofNullable(m.group("value"))))
);
} }
private static List<String> flagsFinal(final List<String> userDefinedJvmOptions) throws InterruptedException, IOException { private static List<String> flagsFinal(final List<String> userDefinedJvmOptions) throws InterruptedException, IOException {
@ -98,12 +102,12 @@ final class JvmErgonomics {
* without having to implement our own JVM option parsing logic. * without having to implement our own JVM option parsing logic.
*/ */
final String java = Paths.get(System.getProperty("java.home"), "bin", "java").toString(); final String java = Paths.get(System.getProperty("java.home"), "bin", "java").toString();
final List<String> command = final List<String> command = Collections.unmodifiableList(
Collections.unmodifiableList(
Stream.of(Stream.of(java), userDefinedJvmOptions.stream(), Stream.of("-XX:+PrintFlagsFinal"), Stream.of("-version")) Stream.of(Stream.of(java), userDefinedJvmOptions.stream(), Stream.of("-XX:+PrintFlagsFinal"), Stream.of("-version"))
.reduce(Stream::concat) .reduce(Stream::concat)
.get() .get()
.collect(Collectors.toList())); .collect(Collectors.toList())
);
final Process process = new ProcessBuilder().command(command).start(); final Process process = new ProcessBuilder().command(command).start();
final List<String> output = readLinesFromInputStream(process.getInputStream()); final List<String> output = readLinesFromInputStream(process.getInputStream());
final List<String> error = readLinesFromInputStream(process.getErrorStream()); final List<String> error = readLinesFromInputStream(process.getErrorStream());
@ -114,7 +118,8 @@ final class JvmErgonomics {
"starting java failed with [%d]\noutput:\n%s\nerror:\n%s", "starting java failed with [%d]\noutput:\n%s\nerror:\n%s",
status, status,
String.join("\n", output), String.join("\n", output),
String.join("\n", error)); String.join("\n", error)
);
throw new RuntimeException(message); throw new RuntimeException(message);
} else { } else {
return output; return output;
@ -122,8 +127,7 @@ final class JvmErgonomics {
} }
private static List<String> readLinesFromInputStream(final InputStream is) throws IOException { private static List<String> readLinesFromInputStream(final InputStream is) throws IOException {
try (InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8); try (InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8); BufferedReader br = new BufferedReader(isr)) {
BufferedReader br = new BufferedReader(isr)) {
return Collections.unmodifiableList(br.lines().collect(Collectors.toList())); return Collections.unmodifiableList(br.lines().collect(Collectors.toList()));
} }
} }

View File

@ -59,19 +59,17 @@ final class JvmOptionsParser {
} }
final List<String> jvmOptions = new ArrayList<>(); final List<String> jvmOptions = new ArrayList<>();
final SortedMap<Integer, String> invalidLines = new TreeMap<>(); final SortedMap<Integer, String> invalidLines = new TreeMap<>();
try (InputStream is = Files.newInputStream(Paths.get(args[0])); try (
InputStream is = Files.newInputStream(Paths.get(args[0]));
Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8); Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(reader)) { BufferedReader br = new BufferedReader(reader)
parse( ) {
JavaVersion.majorVersion(JavaVersion.CURRENT), parse(JavaVersion.majorVersion(JavaVersion.CURRENT), br, new JvmOptionConsumer() {
br,
new JvmOptionConsumer() {
@Override @Override
public void accept(final String jvmOption) { public void accept(final String jvmOption) {
jvmOptions.add(jvmOption); jvmOptions.add(jvmOption);
} }
}, }, new InvalidLineConsumer() {
new InvalidLineConsumer() {
@Override @Override
public void accept(final int lineNumber, final String line) { public void accept(final int lineNumber, final String line) {
invalidLines.put(lineNumber, line); invalidLines.put(lineNumber, line);
@ -83,16 +81,19 @@ final class JvmOptionsParser {
// now append the JVM options from ES_JAVA_OPTS // now append the JVM options from ES_JAVA_OPTS
final String environmentJvmOptions = System.getenv("ES_JAVA_OPTS"); final String environmentJvmOptions = System.getenv("ES_JAVA_OPTS");
if (environmentJvmOptions != null) { if (environmentJvmOptions != null) {
jvmOptions.addAll(Arrays.stream(environmentJvmOptions.split("\\s+")) jvmOptions.addAll(
.filter(s -> s.trim().isEmpty() == false) Arrays.stream(environmentJvmOptions.split("\\s+")).filter(s -> s.trim().isEmpty() == false).collect(Collectors.toList())
.collect(Collectors.toList())); );
} }
final List<String> substitutedJvmOptions = final List<String> substitutedJvmOptions = substitutePlaceholders(
substitutePlaceholders(jvmOptions, Collections.singletonMap("ES_TMPDIR", System.getenv("ES_TMPDIR"))); jvmOptions,
Collections.singletonMap("ES_TMPDIR", System.getenv("ES_TMPDIR"))
);
final List<String> ergonomicJvmOptions = JvmErgonomics.choose(substitutedJvmOptions); final List<String> ergonomicJvmOptions = JvmErgonomics.choose(substitutedJvmOptions);
final List<String> systemJvmOptions = SystemJvmOptions.systemJvmOptions(); final List<String> systemJvmOptions = SystemJvmOptions.systemJvmOptions();
final List<String> finalJvmOptions = final List<String> finalJvmOptions = new ArrayList<>(
new ArrayList<>(systemJvmOptions.size() + substitutedJvmOptions.size() + ergonomicJvmOptions.size()); systemJvmOptions.size() + substitutedJvmOptions.size() + ergonomicJvmOptions.size()
);
finalJvmOptions.addAll(systemJvmOptions); // add the system JVM options first so that they can be overridden finalJvmOptions.addAll(systemJvmOptions); // add the system JVM options first so that they can be overridden
finalJvmOptions.addAll(substitutedJvmOptions); finalJvmOptions.addAll(substitutedJvmOptions);
finalJvmOptions.addAll(ergonomicJvmOptions); finalJvmOptions.addAll(ergonomicJvmOptions);
@ -105,7 +106,8 @@ final class JvmOptionsParser {
"encountered [%d] error%s parsing [%s]", "encountered [%d] error%s parsing [%s]",
invalidLines.size(), invalidLines.size(),
invalidLines.size() == 1 ? "" : "s", invalidLines.size() == 1 ? "" : "s",
args[0]); args[0]
);
Launchers.errPrintln(errorMessage); Launchers.errPrintln(errorMessage);
int count = 0; int count = 0;
for (final Map.Entry<Integer, String> entry : invalidLines.entrySet()) { for (final Map.Entry<Integer, String> entry : invalidLines.entrySet()) {
@ -115,7 +117,8 @@ final class JvmOptionsParser {
"[%d]: encountered improperly formatted JVM option line [%s] on line number [%d]", "[%d]: encountered improperly formatted JVM option line [%s] on line number [%d]",
count, count,
entry.getValue(), entry.getValue(),
entry.getKey()); entry.getKey()
);
Launchers.errPrintln(message); Launchers.errPrintln(message);
} }
Launchers.exit(1); Launchers.exit(1);
@ -123,11 +126,10 @@ final class JvmOptionsParser {
} }
static List<String> substitutePlaceholders(final List<String> jvmOptions, final Map<String, String> substitutions) { static List<String> substitutePlaceholders(final List<String> jvmOptions, final Map<String, String> substitutions) {
final Map<String, String> placeholderSubstitutions = final Map<String, String> placeholderSubstitutions = substitutions.entrySet()
substitutions.entrySet().stream().collect(Collectors.toMap(e -> "${" + e.getKey() + "}", Map.Entry::getValue)); .stream()
return jvmOptions.stream() .collect(Collectors.toMap(e -> "${" + e.getKey() + "}", Map.Entry::getValue));
.map( return jvmOptions.stream().map(jvmOption -> {
jvmOption -> {
String actualJvmOption = jvmOption; String actualJvmOption = jvmOption;
int start = jvmOption.indexOf("${"); int start = jvmOption.indexOf("${");
if (start >= 0 && jvmOption.indexOf('}', start) > 0) { if (start >= 0 && jvmOption.indexOf('}', start) > 0) {
@ -136,8 +138,7 @@ final class JvmOptionsParser {
} }
} }
return actualJvmOption; return actualJvmOption;
}) }).collect(Collectors.toList());
.collect(Collectors.toList());
} }
/** /**
@ -226,7 +227,8 @@ final class JvmOptionsParser {
final int javaMajorVersion, final int javaMajorVersion,
final BufferedReader br, final BufferedReader br,
final JvmOptionConsumer jvmOptionConsumer, final JvmOptionConsumer jvmOptionConsumer,
final InvalidLineConsumer invalidLineConsumer) throws IOException { final InvalidLineConsumer invalidLineConsumer
) throws IOException {
int lineNumber = 0; int lineNumber = 0;
while (true) { while (true) {
final String line = br.readLine(); final String line = br.readLine();

View File

@ -28,10 +28,11 @@ import java.util.List;
final class SystemJvmOptions { final class SystemJvmOptions {
static List<String> systemJvmOptions() { static List<String> systemJvmOptions() {
return Collections.unmodifiableList(Arrays.asList( return Collections.unmodifiableList(
Arrays.asList(
/* /*
* Cache ttl in seconds for positive DNS lookups noting that this overrides the JDK security property networkaddress.cache.ttl; * Cache ttl in seconds for positive DNS lookups noting that this overrides the JDK security property
* can be set to -1 to cache forever. * networkaddress.cache.ttl; can be set to -1 to cache forever.
*/ */
"-Des.networkaddress.cache.ttl=60", "-Des.networkaddress.cache.ttl=60",
/* /*
@ -63,7 +64,9 @@ final class SystemJvmOptions {
"-Dlog4j.shutdownHookEnabled=false", "-Dlog4j.shutdownHookEnabled=false",
"-Dlog4j2.disable.jmx=true", "-Dlog4j2.disable.jmx=true",
javaLocaleProviders())); javaLocaleProviders()
)
);
} }
private static String javaLocaleProviders() { private static String javaLocaleProviders() {
@ -77,7 +80,7 @@ final class SystemJvmOptions {
* //TODO COMPAT will be deprecated in jdk14 https://bugs.openjdk.java.net/browse/JDK-8232906 * //TODO COMPAT will be deprecated in jdk14 https://bugs.openjdk.java.net/browse/JDK-8232906
* See also: documentation in <code>server/org.elasticsearch.common.time.IsoCalendarDataProvider</code> * See also: documentation in <code>server/org.elasticsearch.common.time.IsoCalendarDataProvider</code>
*/ */
if(JavaVersion.majorVersion(JavaVersion.CURRENT) == 8){ if (JavaVersion.majorVersion(JavaVersion.CURRENT) == 8) {
return "-Djava.locale.providers=SPI,JRE"; return "-Djava.locale.providers=SPI,JRE";
} else { } else {
return "-Djava.locale.providers=SPI,COMPAT"; return "-Djava.locale.providers=SPI,COMPAT";

View File

@ -45,23 +45,20 @@ import static org.junit.Assert.fail;
public class JvmErgonomicsTests extends LaunchersTestCase { public class JvmErgonomicsTests extends LaunchersTestCase {
public void testExtractValidHeapSizeUsingXmx() throws InterruptedException, IOException { public void testExtractValidHeapSizeUsingXmx() throws InterruptedException, IOException {
assertThat( assertThat(JvmErgonomics.extractHeapSize(JvmErgonomics.finalJvmOptions(Collections.singletonList("-Xmx2g"))), equalTo(2L << 30));
JvmErgonomics.extractHeapSize(JvmErgonomics.finalJvmOptions(Collections.singletonList("-Xmx2g"))),
equalTo(2L << 30));
} }
public void testExtractValidHeapSizeUsingMaxHeapSize() throws InterruptedException, IOException { public void testExtractValidHeapSizeUsingMaxHeapSize() throws InterruptedException, IOException {
assertThat( assertThat(
JvmErgonomics.extractHeapSize(JvmErgonomics.finalJvmOptions(Collections.singletonList("-XX:MaxHeapSize=2g"))), JvmErgonomics.extractHeapSize(JvmErgonomics.finalJvmOptions(Collections.singletonList("-XX:MaxHeapSize=2g"))),
equalTo(2L << 30)); equalTo(2L << 30)
);
} }
public void testExtractValidHeapSizeNoOptionPresent() throws InterruptedException, IOException { public void testExtractValidHeapSizeNoOptionPresent() throws InterruptedException, IOException {
// Muted for jdk8/Windows, see: https://github.com/elastic/elasticsearch/issues/47384 // Muted for jdk8/Windows, see: https://github.com/elastic/elasticsearch/issues/47384
assumeFalse(System.getProperty("os.name").startsWith("Windows") && JavaVersion.majorVersion(JavaVersion.CURRENT) == 8); assumeFalse(System.getProperty("os.name").startsWith("Windows") && JavaVersion.majorVersion(JavaVersion.CURRENT) == 8);
assertThat( assertThat(JvmErgonomics.extractHeapSize(JvmErgonomics.finalJvmOptions(Collections.emptyList())), greaterThan(0L));
JvmErgonomics.extractHeapSize(JvmErgonomics.finalJvmOptions(Collections.emptyList())),
greaterThan(0L));
} }
public void testHeapSizeInvalid() throws InterruptedException, IOException { public void testHeapSizeInvalid() throws InterruptedException, IOException {
@ -82,7 +79,8 @@ public class JvmErgonomicsTests extends LaunchersTestCase {
assertThat(e, hasToString(containsString(("starting java failed")))); assertThat(e, hasToString(containsString(("starting java failed"))));
assertThat( assertThat(
e, e,
anyOf(hasToString(containsString("Too small initial heap")), hasToString(containsString("Too small maximum heap")))); anyOf(hasToString(containsString("Too small initial heap")), hasToString(containsString("Too small maximum heap")))
);
} }
} }
@ -99,14 +97,17 @@ public class JvmErgonomicsTests extends LaunchersTestCase {
public void testMaxDirectMemorySizeUnset() throws InterruptedException, IOException { public void testMaxDirectMemorySizeUnset() throws InterruptedException, IOException {
assertThat( assertThat(
JvmErgonomics.extractMaxDirectMemorySize(JvmErgonomics.finalJvmOptions(Collections.singletonList("-Xmx1g"))), JvmErgonomics.extractMaxDirectMemorySize(JvmErgonomics.finalJvmOptions(Collections.singletonList("-Xmx1g"))),
equalTo(0L)); equalTo(0L)
);
} }
public void testMaxDirectMemorySizeSet() throws InterruptedException, IOException { public void testMaxDirectMemorySizeSet() throws InterruptedException, IOException {
assertThat( assertThat(
JvmErgonomics.extractMaxDirectMemorySize(JvmErgonomics.finalJvmOptions( JvmErgonomics.extractMaxDirectMemorySize(
Arrays.asList("-Xmx1g", "-XX:MaxDirectMemorySize=512m"))), JvmErgonomics.finalJvmOptions(Arrays.asList("-Xmx1g", "-XX:MaxDirectMemorySize=512m"))
equalTo(512L << 20)); ),
equalTo(512L << 20)
);
} }
public void testExtractSystemProperties() { public void testExtractSystemProperties() {
@ -115,7 +116,8 @@ public class JvmErgonomicsTests extends LaunchersTestCase {
expectedSystemProperties.put("kv.setting", "ABC=DEF"); expectedSystemProperties.put("kv.setting", "ABC=DEF");
Map<String, String> parsedSystemProperties = JvmErgonomics.extractSystemProperties( Map<String, String> parsedSystemProperties = JvmErgonomics.extractSystemProperties(
Arrays.asList("-Dfile.encoding=UTF-8", "-Dkv.setting=ABC=DEF")); Arrays.asList("-Dfile.encoding=UTF-8", "-Dkv.setting=ABC=DEF")
);
assertEquals(expectedSystemProperties, parsedSystemProperties); assertEquals(expectedSystemProperties, parsedSystemProperties);
} }
@ -139,7 +141,8 @@ public class JvmErgonomicsTests extends LaunchersTestCase {
final String heapSize = randomFrom(heapMaxDirectMemorySize.keySet().toArray(new String[0])); final String heapSize = randomFrom(heapMaxDirectMemorySize.keySet().toArray(new String[0]));
assertThat( assertThat(
JvmErgonomics.choose(Arrays.asList("-Xms" + heapSize, "-Xmx" + heapSize)), JvmErgonomics.choose(Arrays.asList("-Xms" + heapSize, "-Xmx" + heapSize)),
hasItem("-XX:MaxDirectMemorySize=" + heapMaxDirectMemorySize.get(heapSize))); hasItem("-XX:MaxDirectMemorySize=" + heapMaxDirectMemorySize.get(heapSize))
);
} }
public void testMaxDirectMemorySizeChoiceWhenSet() throws InterruptedException, IOException { public void testMaxDirectMemorySizeChoiceWhenSet() throws InterruptedException, IOException {
@ -147,7 +150,8 @@ public class JvmErgonomicsTests extends LaunchersTestCase {
assertThat( assertThat(
derivedSettingList, derivedSettingList,
// if MaxDirectMemorySize is set, we shouldn't derive our own value for it // if MaxDirectMemorySize is set, we shouldn't derive our own value for it
everyItem(not(startsWith("-XX:MaxDirectMemorySize=")))); everyItem(not(startsWith("-XX:MaxDirectMemorySize=")))
);
} }
} }

View File

@ -43,13 +43,13 @@ public class JvmOptionsParserTests extends LaunchersTestCase {
public void testSubstitution() { public void testSubstitution() {
final List<String> jvmOptions = JvmOptionsParser.substitutePlaceholders( final List<String> jvmOptions = JvmOptionsParser.substitutePlaceholders(
Collections.singletonList("-Djava.io.tmpdir=${ES_TMPDIR}"), Collections.singletonList("-Djava.io.tmpdir=${ES_TMPDIR}"),
Collections.singletonMap("ES_TMPDIR", "/tmp/elasticsearch")); Collections.singletonMap("ES_TMPDIR", "/tmp/elasticsearch")
);
assertThat(jvmOptions, contains("-Djava.io.tmpdir=/tmp/elasticsearch")); assertThat(jvmOptions, contains("-Djava.io.tmpdir=/tmp/elasticsearch"));
} }
public void testUnversionedOptions() throws IOException { public void testUnversionedOptions() throws IOException {
try (StringReader sr = new StringReader("-Xms1g\n-Xmx1g"); try (StringReader sr = new StringReader("-Xms1g\n-Xmx1g"); BufferedReader br = new BufferedReader(sr)) {
BufferedReader br = new BufferedReader(sr)) {
assertExpectedJvmOptions(randomIntBetween(8, Integer.MAX_VALUE), br, Arrays.asList("-Xms1g", "-Xmx1g")); assertExpectedJvmOptions(randomIntBetween(8, Integer.MAX_VALUE), br, Arrays.asList("-Xms1g", "-Xmx1g"));
} }
@ -59,14 +59,18 @@ public class JvmOptionsParserTests extends LaunchersTestCase {
final int javaMajorVersion = randomIntBetween(8, Integer.MAX_VALUE - 1); final int javaMajorVersion = randomIntBetween(8, Integer.MAX_VALUE - 1);
final int smallerJavaMajorVersion = randomIntBetween(7, javaMajorVersion); final int smallerJavaMajorVersion = randomIntBetween(7, javaMajorVersion);
final int largerJavaMajorVersion = randomIntBetween(javaMajorVersion + 1, Integer.MAX_VALUE); final int largerJavaMajorVersion = randomIntBetween(javaMajorVersion + 1, Integer.MAX_VALUE);
try (StringReader sr = new StringReader( try (
StringReader sr = new StringReader(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"-Xms1g\n%d:-Xmx1g\n%d:-XX:+UseG1GC\n%d:-Xlog:gc", "-Xms1g\n%d:-Xmx1g\n%d:-XX:+UseG1GC\n%d:-Xlog:gc",
javaMajorVersion, javaMajorVersion,
smallerJavaMajorVersion, smallerJavaMajorVersion,
largerJavaMajorVersion)); largerJavaMajorVersion
BufferedReader br = new BufferedReader(sr)) { )
);
BufferedReader br = new BufferedReader(sr)
) {
assertExpectedJvmOptions(javaMajorVersion, br, Arrays.asList("-Xms1g", "-Xmx1g")); assertExpectedJvmOptions(javaMajorVersion, br, Arrays.asList("-Xms1g", "-Xmx1g"));
} }
} }
@ -75,14 +79,18 @@ public class JvmOptionsParserTests extends LaunchersTestCase {
final int javaMajorVersion = randomIntBetween(8, Integer.MAX_VALUE - 1); final int javaMajorVersion = randomIntBetween(8, Integer.MAX_VALUE - 1);
final int smallerJavaMajorVersion = randomIntBetween(7, javaMajorVersion); final int smallerJavaMajorVersion = randomIntBetween(7, javaMajorVersion);
final int largerJavaMajorVersion = randomIntBetween(javaMajorVersion + 1, Integer.MAX_VALUE); final int largerJavaMajorVersion = randomIntBetween(javaMajorVersion + 1, Integer.MAX_VALUE);
try (StringReader sr = new StringReader( try (
StringReader sr = new StringReader(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"-Xms1g\n%d-:-Xmx1g\n%d-:-XX:+UseG1GC\n%d-:-Xlog:gc", "-Xms1g\n%d-:-Xmx1g\n%d-:-XX:+UseG1GC\n%d-:-Xlog:gc",
javaMajorVersion, javaMajorVersion,
smallerJavaMajorVersion, smallerJavaMajorVersion,
largerJavaMajorVersion)); largerJavaMajorVersion
BufferedReader br = new BufferedReader(sr)) { )
);
BufferedReader br = new BufferedReader(sr)
) {
assertExpectedJvmOptions(javaMajorVersion, br, Arrays.asList("-Xms1g", "-Xmx1g", "-XX:+UseG1GC")); assertExpectedJvmOptions(javaMajorVersion, br, Arrays.asList("-Xms1g", "-Xmx1g", "-XX:+UseG1GC"));
} }
} }
@ -94,7 +102,8 @@ public class JvmOptionsParserTests extends LaunchersTestCase {
final int smallerJavaMajorVersionUpperBound = randomIntBetween(smallerJavaMajorVersionLowerBound, javaMajorVersion); final int smallerJavaMajorVersionUpperBound = randomIntBetween(smallerJavaMajorVersionLowerBound, javaMajorVersion);
final int largerJavaMajorVersionLowerBound = randomIntBetween(javaMajorVersion + 1, Integer.MAX_VALUE); final int largerJavaMajorVersionLowerBound = randomIntBetween(javaMajorVersion + 1, Integer.MAX_VALUE);
final int largerJavaMajorVersionUpperBound = randomIntBetween(largerJavaMajorVersionLowerBound, Integer.MAX_VALUE); final int largerJavaMajorVersionUpperBound = randomIntBetween(largerJavaMajorVersionLowerBound, Integer.MAX_VALUE);
try (StringReader sr = new StringReader( try (
StringReader sr = new StringReader(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"-Xms1g\n%d-%d:-Xmx1g\n%d-%d:-XX:+UseG1GC\n%d-%d:-Xlog:gc", "-Xms1g\n%d-%d:-Xmx1g\n%d-%d:-XX:+UseG1GC\n%d-%d:-Xlog:gc",
@ -103,8 +112,11 @@ public class JvmOptionsParserTests extends LaunchersTestCase {
smallerJavaMajorVersionLowerBound, smallerJavaMajorVersionLowerBound,
smallerJavaMajorVersionUpperBound, smallerJavaMajorVersionUpperBound,
largerJavaMajorVersionLowerBound, largerJavaMajorVersionLowerBound,
largerJavaMajorVersionUpperBound)); largerJavaMajorVersionUpperBound
BufferedReader br = new BufferedReader(sr)) { )
);
BufferedReader br = new BufferedReader(sr)
) {
assertExpectedJvmOptions(javaMajorVersion, br, Arrays.asList("-Xms1g", "-Xmx1g")); assertExpectedJvmOptions(javaMajorVersion, br, Arrays.asList("-Xms1g", "-Xmx1g"));
} }
} }
@ -116,7 +128,8 @@ public class JvmOptionsParserTests extends LaunchersTestCase {
final int smallerJavaMajorVersionUpperBound = randomIntBetween(smallerJavaMajorVersionLowerBound, javaMajorVersion); final int smallerJavaMajorVersionUpperBound = randomIntBetween(smallerJavaMajorVersionLowerBound, javaMajorVersion);
final int largerJavaMajorVersionLowerBound = randomIntBetween(javaMajorVersion + 1, Integer.MAX_VALUE); final int largerJavaMajorVersionLowerBound = randomIntBetween(javaMajorVersion + 1, Integer.MAX_VALUE);
final int largerJavaMajorVersionUpperBound = randomIntBetween(largerJavaMajorVersionLowerBound, Integer.MAX_VALUE); final int largerJavaMajorVersionUpperBound = randomIntBetween(largerJavaMajorVersionLowerBound, Integer.MAX_VALUE);
try (StringReader sr = new StringReader( try (
StringReader sr = new StringReader(
String.format( String.format(
Locale.ROOT, Locale.ROOT,
"-Xms1g\n%d:-Xmx1g\n%d-:-XX:+UseG1GC\n%d-%d:-Xlog:gc\n%d-%d:-XX:+PrintFlagsFinal\n%d-%d:-XX+AggressiveOpts", "-Xms1g\n%d:-Xmx1g\n%d-:-XX:+UseG1GC\n%d-%d:-Xlog:gc\n%d-%d:-XX:+PrintFlagsFinal\n%d-%d:-XX+AggressiveOpts",
@ -127,22 +140,22 @@ public class JvmOptionsParserTests extends LaunchersTestCase {
smallerJavaMajorVersionLowerBound, smallerJavaMajorVersionLowerBound,
smallerJavaMajorVersionUpperBound, smallerJavaMajorVersionUpperBound,
largerJavaMajorVersionLowerBound, largerJavaMajorVersionLowerBound,
largerJavaMajorVersionUpperBound)); largerJavaMajorVersionUpperBound
BufferedReader br = new BufferedReader(sr)) { )
);
BufferedReader br = new BufferedReader(sr)
) {
assertExpectedJvmOptions(javaMajorVersion, br, Arrays.asList("-Xms1g", "-Xmx1g", "-XX:+UseG1GC", "-Xlog:gc")); assertExpectedJvmOptions(javaMajorVersion, br, Arrays.asList("-Xms1g", "-Xmx1g", "-XX:+UseG1GC", "-Xlog:gc"));
} }
} }
private void assertExpectedJvmOptions( private void assertExpectedJvmOptions(final int javaMajorVersion, final BufferedReader br, final List<String> expectedJvmOptions)
final int javaMajorVersion, final BufferedReader br, final List<String> expectedJvmOptions) throws IOException { throws IOException {
final Map<String, AtomicBoolean> seenJvmOptions = new HashMap<>(); final Map<String, AtomicBoolean> seenJvmOptions = new HashMap<>();
for (final String expectedJvmOption : expectedJvmOptions) { for (final String expectedJvmOption : expectedJvmOptions) {
assertNull(seenJvmOptions.put(expectedJvmOption, new AtomicBoolean())); assertNull(seenJvmOptions.put(expectedJvmOption, new AtomicBoolean()));
} }
JvmOptionsParser.parse( JvmOptionsParser.parse(javaMajorVersion, br, new JvmOptionsParser.JvmOptionConsumer() {
javaMajorVersion,
br,
new JvmOptionsParser.JvmOptionConsumer() {
@Override @Override
public void accept(final String jvmOption) { public void accept(final String jvmOption) {
final AtomicBoolean seen = seenJvmOptions.get(jvmOption); final AtomicBoolean seen = seenJvmOptions.get(jvmOption);
@ -152,8 +165,7 @@ public class JvmOptionsParserTests extends LaunchersTestCase {
assertFalse("saw JVM option [" + jvmOption + "] more than once", seen.get()); assertFalse("saw JVM option [" + jvmOption + "] more than once", seen.get());
seen.set(true); seen.set(true);
} }
}, }, new JvmOptionsParser.InvalidLineConsumer() {
new JvmOptionsParser.InvalidLineConsumer() {
@Override @Override
public void accept(final int lineNumber, final String line) { public void accept(final int lineNumber, final String line) {
fail("unexpected invalid line [" + line + "] on line number [" + lineNumber + "]"); fail("unexpected invalid line [" + line + "] on line number [" + lineNumber + "]");
@ -165,12 +177,8 @@ public class JvmOptionsParserTests extends LaunchersTestCase {
} }
public void testInvalidLines() throws IOException { public void testInvalidLines() throws IOException {
try (StringReader sr = new StringReader("XX:+UseG1GC"); try (StringReader sr = new StringReader("XX:+UseG1GC"); BufferedReader br = new BufferedReader(sr)) {
BufferedReader br = new BufferedReader(sr)) { JvmOptionsParser.parse(randomIntBetween(8, Integer.MAX_VALUE), br, new JvmOptionsParser.JvmOptionConsumer() {
JvmOptionsParser.parse(
randomIntBetween(8, Integer.MAX_VALUE),
br,
new JvmOptionsParser.JvmOptionConsumer() {
@Override @Override
public void accept(final String jvmOption) { public void accept(final String jvmOption) {
fail("unexpected valid JVM option [" + jvmOption + "]"); fail("unexpected valid JVM option [" + jvmOption + "]");
@ -187,8 +195,7 @@ public class JvmOptionsParserTests extends LaunchersTestCase {
final int javaMajorVersion = randomIntBetween(8, Integer.MAX_VALUE); final int javaMajorVersion = randomIntBetween(8, Integer.MAX_VALUE);
final int smallerJavaMajorVersion = randomIntBetween(7, javaMajorVersion - 1); final int smallerJavaMajorVersion = randomIntBetween(7, javaMajorVersion - 1);
final String invalidRangeLine = String.format(Locale.ROOT, "%d:%d-XX:+UseG1GC", javaMajorVersion, smallerJavaMajorVersion); final String invalidRangeLine = String.format(Locale.ROOT, "%d:%d-XX:+UseG1GC", javaMajorVersion, smallerJavaMajorVersion);
try (StringReader sr = new StringReader(invalidRangeLine); try (StringReader sr = new StringReader(invalidRangeLine); BufferedReader br = new BufferedReader(sr)) {
BufferedReader br = new BufferedReader(sr)) {
assertInvalidLines(br, Collections.singletonMap(1, invalidRangeLine)); assertInvalidLines(br, Collections.singletonMap(1, invalidRangeLine));
} }
@ -198,9 +205,9 @@ public class JvmOptionsParserTests extends LaunchersTestCase {
Locale.ROOT, Locale.ROOT,
"%d:-XX:+UseG1GC\n8-%d:-XX:+AggressiveOpts", "%d:-XX:+UseG1GC\n8-%d:-XX:+AggressiveOpts",
invalidLowerJavaMajorVersion, invalidLowerJavaMajorVersion,
invalidUpperJavaMajorVersion); invalidUpperJavaMajorVersion
try (StringReader sr = new StringReader(numberFormatExceptionsLine); );
BufferedReader br = new BufferedReader(sr)) { try (StringReader sr = new StringReader(numberFormatExceptionsLine); BufferedReader br = new BufferedReader(sr)) {
final Map<Integer, String> invalidLines = new HashMap<>(2); final Map<Integer, String> invalidLines = new HashMap<>(2);
invalidLines.put(1, String.format(Locale.ROOT, "%d:-XX:+UseG1GC", invalidLowerJavaMajorVersion)); invalidLines.put(1, String.format(Locale.ROOT, "%d:-XX:+UseG1GC", invalidLowerJavaMajorVersion));
invalidLines.put(2, String.format(Locale.ROOT, "8-%d:-XX:+AggressiveOpts", invalidUpperJavaMajorVersion)); invalidLines.put(2, String.format(Locale.ROOT, "8-%d:-XX:+AggressiveOpts", invalidUpperJavaMajorVersion));
@ -208,8 +215,7 @@ public class JvmOptionsParserTests extends LaunchersTestCase {
} }
final String multipleInvalidLines = "XX:+UseG1GC\nXX:+AggressiveOpts"; final String multipleInvalidLines = "XX:+UseG1GC\nXX:+AggressiveOpts";
try (StringReader sr = new StringReader(multipleInvalidLines); try (StringReader sr = new StringReader(multipleInvalidLines); BufferedReader br = new BufferedReader(sr)) {
BufferedReader br = new BufferedReader(sr)) {
final Map<Integer, String> invalidLines = new HashMap<>(2); final Map<Integer, String> invalidLines = new HashMap<>(2);
invalidLines.put(1, "XX:+UseG1GC"); invalidLines.put(1, "XX:+UseG1GC");
invalidLines.put(2, "XX:+AggressiveOpts"); invalidLines.put(2, "XX:+AggressiveOpts");
@ -219,24 +225,19 @@ public class JvmOptionsParserTests extends LaunchersTestCase {
final int lowerBound = randomIntBetween(9, 16); final int lowerBound = randomIntBetween(9, 16);
final int upperBound = randomIntBetween(8, lowerBound - 1); final int upperBound = randomIntBetween(8, lowerBound - 1);
final String upperBoundGreaterThanLowerBound = String.format(Locale.ROOT, "%d-%d-XX:+UseG1GC", lowerBound, upperBound); final String upperBoundGreaterThanLowerBound = String.format(Locale.ROOT, "%d-%d-XX:+UseG1GC", lowerBound, upperBound);
try (StringReader sr = new StringReader(upperBoundGreaterThanLowerBound); try (StringReader sr = new StringReader(upperBoundGreaterThanLowerBound); BufferedReader br = new BufferedReader(sr)) {
BufferedReader br = new BufferedReader(sr)) {
assertInvalidLines(br, Collections.singletonMap(1, upperBoundGreaterThanLowerBound)); assertInvalidLines(br, Collections.singletonMap(1, upperBoundGreaterThanLowerBound));
} }
} }
private void assertInvalidLines(final BufferedReader br, final Map<Integer, String> invalidLines) throws IOException { private void assertInvalidLines(final BufferedReader br, final Map<Integer, String> invalidLines) throws IOException {
final Map<Integer, String> seenInvalidLines = new HashMap<>(invalidLines.size()); final Map<Integer, String> seenInvalidLines = new HashMap<>(invalidLines.size());
JvmOptionsParser.parse( JvmOptionsParser.parse(randomIntBetween(8, Integer.MAX_VALUE), br, new JvmOptionsParser.JvmOptionConsumer() {
randomIntBetween(8, Integer.MAX_VALUE),
br,
new JvmOptionsParser.JvmOptionConsumer() {
@Override @Override
public void accept(final String jvmOption) { public void accept(final String jvmOption) {
fail("unexpected valid JVM options [" + jvmOption + "]"); fail("unexpected valid JVM options [" + jvmOption + "]");
} }
}, }, new JvmOptionsParser.InvalidLineConsumer() {
new JvmOptionsParser.InvalidLineConsumer() {
@Override @Override
public void accept(final int lineNumber, final String line) { public void accept(final int lineNumber, final String line) {
seenInvalidLines.put(lineNumber, line); seenInvalidLines.put(lineNumber, line);
@ -250,7 +251,8 @@ public class JvmOptionsParserTests extends LaunchersTestCase {
assertThat(JvmOptionsParser.spaceDelimitJvmOptions(Arrays.asList("-Xms1g", "-Xmx1g")), equalTo("-Xms1g -Xmx1g")); assertThat(JvmOptionsParser.spaceDelimitJvmOptions(Arrays.asList("-Xms1g", "-Xmx1g")), equalTo("-Xms1g -Xmx1g"));
assertThat( assertThat(
JvmOptionsParser.spaceDelimitJvmOptions(Arrays.asList("-Xms1g", "-Xmx1g", "-XX:+UseG1GC")), JvmOptionsParser.spaceDelimitJvmOptions(Arrays.asList("-Xms1g", "-Xmx1g", "-XX:+UseG1GC")),
equalTo("-Xms1g -Xmx1g -XX:+UseG1GC")); equalTo("-Xms1g -Xmx1g -XX:+UseG1GC")
);
} }
} }

View File

@ -31,15 +31,12 @@ import com.carrotsearch.randomizedtesting.annotations.ThreadLeakScope;
import com.carrotsearch.randomizedtesting.annotations.ThreadLeakZombies; import com.carrotsearch.randomizedtesting.annotations.ThreadLeakZombies;
import com.carrotsearch.randomizedtesting.annotations.TimeoutSuite; import com.carrotsearch.randomizedtesting.annotations.TimeoutSuite;
@TestMethodProviders({ @TestMethodProviders({ JUnit3MethodProvider.class })
JUnit3MethodProvider.class @SeedDecorators({ MixWithSuiteName.class })
})
@SeedDecorators({MixWithSuiteName.class})
@ThreadLeakScope(ThreadLeakScope.Scope.SUITE) @ThreadLeakScope(ThreadLeakScope.Scope.SUITE)
@ThreadLeakGroup(ThreadLeakGroup.Group.MAIN) @ThreadLeakGroup(ThreadLeakGroup.Group.MAIN)
@ThreadLeakAction({ThreadLeakAction.Action.WARN, ThreadLeakAction.Action.INTERRUPT}) @ThreadLeakAction({ ThreadLeakAction.Action.WARN, ThreadLeakAction.Action.INTERRUPT })
@ThreadLeakZombies(ThreadLeakZombies.Consequence.IGNORE_REMAINING_TESTS) @ThreadLeakZombies(ThreadLeakZombies.Consequence.IGNORE_REMAINING_TESTS)
@ThreadLeakLingering(linger = 5000) @ThreadLeakLingering(linger = 5000)
@TimeoutSuite(millis = 2 * 60 * 60 * 1000) @TimeoutSuite(millis = 2 * 60 * 60 * 1000)
abstract class LaunchersTestCase extends RandomizedTest { abstract class LaunchersTestCase extends RandomizedTest {}
}

View File

@ -134,8 +134,10 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
/** The builtin modules, which are plugins, but cannot be installed or removed. */ /** The builtin modules, which are plugins, but cannot be installed or removed. */
static final Set<String> MODULES; static final Set<String> MODULES;
static { static {
try (InputStream stream = InstallPluginCommand.class.getResourceAsStream("/modules.txt"); try (
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { InputStream stream = InstallPluginCommand.class.getResourceAsStream("/modules.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))
) {
Set<String> modules = new HashSet<>(); Set<String> modules = new HashSet<>();
String line = reader.readLine(); String line = reader.readLine();
while (line != null) { while (line != null) {
@ -151,8 +153,10 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
/** The official plugins that can be installed simply by name. */ /** The official plugins that can be installed simply by name. */
static final Set<String> OFFICIAL_PLUGINS; static final Set<String> OFFICIAL_PLUGINS;
static { static {
try (InputStream stream = InstallPluginCommand.class.getResourceAsStream("/plugins.txt"); try (
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { InputStream stream = InstallPluginCommand.class.getResourceAsStream("/plugins.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))
) {
Set<String> plugins = new TreeSet<>(); // use tree set to get sorting for help command Set<String> plugins = new TreeSet<>(); // use tree set to get sorting for help command
String line = reader.readLine(); String line = reader.readLine();
while (line != null) { while (line != null) {
@ -197,8 +201,10 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
InstallPluginCommand() { InstallPluginCommand() {
super("Install a plugin"); super("Install a plugin");
this.batchOption = parser.acceptsAll(Arrays.asList("b", "batch"), this.batchOption = parser.acceptsAll(
"Enable batch mode explicitly, automatic confirmation of security permission"); Arrays.asList("b", "batch"),
"Enable batch mode explicitly, automatic confirmation of security permission"
);
this.arguments = parser.nonOptions("plugin id"); this.arguments = parser.nonOptions("plugin id");
} }
@ -261,7 +267,8 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
} catch (final IOException exceptionWhileRemovingFiles) { } catch (final IOException exceptionWhileRemovingFiles) {
final Exception exception = new Exception( final Exception exception = new Exception(
"failed rolling back installation of [" + deleteOnFailureEntry.getKey() + "]", "failed rolling back installation of [" + deleteOnFailureEntry.getKey() + "]",
exceptionWhileRemovingFiles); exceptionWhileRemovingFiles
);
installProblem.addSuppressed(exception); installProblem.addSuppressed(exception);
terminal.println("-> Failed rolling back " + deleteOnFailureEntry.getKey()); terminal.println("-> Failed rolling back " + deleteOnFailureEntry.getKey());
} }
@ -285,7 +292,8 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
case OSS: case OSS:
throw new UserException( throw new UserException(
ExitCodes.CONFIG, ExitCodes.CONFIG,
"X-Pack is not available with the oss distribution; to use X-Pack features use the default distribution"); "X-Pack is not available with the oss distribution; to use X-Pack features use the default distribution"
);
case UNKNOWN: case UNKNOWN:
throw new IllegalStateException("your distribution is broken"); throw new IllegalStateException("your distribution is broken");
} }
@ -313,7 +321,7 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
List<String> plugins = checkMisspelledPlugin(pluginId); List<String> plugins = checkMisspelledPlugin(pluginId);
String msg = "Unknown plugin " + pluginId; String msg = "Unknown plugin " + pluginId;
if (plugins.isEmpty() == false) { if (plugins.isEmpty() == false) {
msg += ", did you mean " + (plugins.size() == 1 ? "[" + plugins.get(0) + "]": "any of " + plugins.toString()) + "?"; msg += ", did you mean " + (plugins.size() == 1 ? "[" + plugins.get(0) + "]" : "any of " + plugins.toString()) + "?";
} }
throw new UserException(ExitCodes.USAGE, msg); throw new UserException(ExitCodes.USAGE, msg);
} }
@ -337,11 +345,15 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
final Version version, final Version version,
final boolean isSnapshot, final boolean isSnapshot,
final String pluginId, final String pluginId,
final String platform) throws IOException, UserException { final String platform
) throws IOException,
UserException {
final String baseUrl; final String baseUrl;
if (isSnapshot && stagingHash == null) { if (isSnapshot && stagingHash == null) {
throw new UserException( throw new UserException(
ExitCodes.CONFIG, "attempted to install release build of official plugin on snapshot build of Elasticsearch"); ExitCodes.CONFIG,
"attempted to install release build of official plugin on snapshot build of Elasticsearch"
);
} }
if (stagingHash != null) { if (stagingHash != null) {
if (isSnapshot) { if (isSnapshot) {
@ -352,8 +364,14 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
} else { } else {
baseUrl = String.format(Locale.ROOT, "https://artifacts.elastic.co/downloads/elasticsearch-plugins/%s", pluginId); baseUrl = String.format(Locale.ROOT, "https://artifacts.elastic.co/downloads/elasticsearch-plugins/%s", pluginId);
} }
final String platformUrl = final String platformUrl = String.format(
String.format(Locale.ROOT, "%s/%s-%s-%s.zip", baseUrl, pluginId, platform, Build.CURRENT.getQualifiedVersion()); Locale.ROOT,
"%s/%s-%s-%s.zip",
baseUrl,
pluginId,
platform,
Build.CURRENT.getQualifiedVersion()
);
if (urlExists(terminal, platformUrl)) { if (urlExists(terminal, platformUrl)) {
return platformUrl; return platformUrl;
} }
@ -362,7 +380,13 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
private String nonReleaseUrl(final String hostname, final Version version, final String stagingHash, final String pluginId) { private String nonReleaseUrl(final String hostname, final Version version, final String stagingHash, final String pluginId) {
return String.format( return String.format(
Locale.ROOT, "https://%s.elastic.co/%s-%s/downloads/elasticsearch-plugins/%s", hostname, version, stagingHash, pluginId); Locale.ROOT,
"https://%s.elastic.co/%s-%s/downloads/elasticsearch-plugins/%s",
hostname,
version,
stagingHash,
pluginId
);
} }
/** Returns the url for an elasticsearch plugin in maven. */ /** Returns the url for an elasticsearch plugin in maven. */
@ -419,8 +443,11 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
Path zip = Files.createTempFile(tmpDir, null, ".zip"); Path zip = Files.createTempFile(tmpDir, null, ".zip");
URLConnection urlConnection = url.openConnection(); URLConnection urlConnection = url.openConnection();
urlConnection.addRequestProperty("User-Agent", "elasticsearch-plugin-installer"); urlConnection.addRequestProperty("User-Agent", "elasticsearch-plugin-installer");
try (InputStream in = isBatch ? urlConnection.getInputStream() : try (
new TerminalProgressInputStream(urlConnection.getInputStream(),urlConnection.getContentLength(),terminal)) { InputStream in = isBatch
? urlConnection.getInputStream()
: new TerminalProgressInputStream(urlConnection.getInputStream(), urlConnection.getContentLength(), terminal)
) {
// must overwrite since creating the temp file above actually created the file // must overwrite since creating the temp file above actually created the file
Files.copy(in, zip, StandardCopyOption.REPLACE_EXISTING); Files.copy(in, zip, StandardCopyOption.REPLACE_EXISTING);
} }
@ -493,7 +520,11 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
final Terminal terminal, final Terminal terminal,
final String urlString, final String urlString,
final Path tmpDir, final Path tmpDir,
final boolean officialPlugin, boolean isBatch) throws IOException, PGPException, UserException { final boolean officialPlugin,
boolean isBatch
) throws IOException,
PGPException,
UserException {
Path zip = downloadZip(terminal, urlString, tmpDir, isBatch); Path zip = downloadZip(terminal, urlString, tmpDir, isBatch);
pathsToDeleteOnShutdown.add(zip); pathsToDeleteOnShutdown.add(zip);
String checksumUrlString = urlString + ".sha512"; String checksumUrlString = urlString + ".sha512";
@ -501,8 +532,10 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
String digestAlgo = "SHA-512"; String digestAlgo = "SHA-512";
if (checksumUrl == null && officialPlugin == false) { if (checksumUrl == null && officialPlugin == false) {
// fallback to sha1, until 7.0, but with warning // fallback to sha1, until 7.0, but with warning
terminal.println("Warning: sha512 not found, falling back to sha1. This behavior is deprecated and will be removed in a " + terminal.println(
"future release. Please update the plugin to use a sha512 checksum."); "Warning: sha512 not found, falling back to sha1. This behavior is deprecated and will be removed in a "
+ "future release. Please update the plugin to use a sha512 checksum."
);
checksumUrlString = urlString + ".sha1"; checksumUrlString = urlString + ".sha1";
checksumUrl = openUrl(checksumUrlString); checksumUrl = openUrl(checksumUrlString);
digestAlgo = "SHA-1"; digestAlgo = "SHA-1";
@ -540,7 +573,8 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
"checksum file at [%s] is not for this plugin, expected [%s] but was [%s]", "checksum file at [%s] is not for this plugin, expected [%s] but was [%s]",
checksumUrl, checksumUrl,
expectedFile, expectedFile,
fields[1]); fields[1]
);
throw new UserException(ExitCodes.IO_ERROR, message); throw new UserException(ExitCodes.IO_ERROR, message);
} }
if (checksumReader.readLine() != null) { if (checksumReader.readLine() != null) {
@ -563,7 +597,8 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
if (expectedChecksum.equals(actualChecksum) == false) { if (expectedChecksum.equals(actualChecksum) == false) {
throw new UserException( throw new UserException(
ExitCodes.IO_ERROR, ExitCodes.IO_ERROR,
digestAlgo + " mismatch, expected " + expectedChecksum + " but got " + actualChecksum); digestAlgo + " mismatch, expected " + expectedChecksum + " but got " + actualChecksum
);
} }
} catch (final NoSuchAlgorithmException e) { } catch (final NoSuchAlgorithmException e) {
// this should never happen as we are using SHA-1 and SHA-512 here // this should never happen as we are using SHA-1 and SHA-512 here
@ -596,7 +631,8 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
// sin is a URL stream to the signature corresponding to the downloaded plugin zip // sin is a URL stream to the signature corresponding to the downloaded plugin zip
InputStream sin = urlOpenStream(ascUrl); InputStream sin = urlOpenStream(ascUrl);
// ain is a input stream to the public key in ASCII-Armor format (RFC4880) // ain is a input stream to the public key in ASCII-Armor format (RFC4880)
InputStream ain = new ArmoredInputStream(getPublicKey())) { InputStream ain = new ArmoredInputStream(getPublicKey())
) {
final JcaPGPObjectFactory factory = new JcaPGPObjectFactory(PGPUtil.getDecoderStream(sin)); final JcaPGPObjectFactory factory = new JcaPGPObjectFactory(PGPUtil.getDecoderStream(sin));
final PGPSignature signature = ((PGPSignatureList) factory.nextObject()).get(0); final PGPSignature signature = ((PGPSignatureList) factory.nextObject()).get(0);
@ -660,7 +696,7 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
// pkg private for tests // pkg private for tests
URL openUrl(String urlString) throws IOException { URL openUrl(String urlString) throws IOException {
URL checksumUrl = new URL(urlString); URL checksumUrl = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection)checksumUrl.openConnection(); HttpURLConnection connection = (HttpURLConnection) checksumUrl.openConnection();
if (connection.getResponseCode() == 404) { if (connection.getResponseCode() == 404) {
return null; return null;
} }
@ -678,8 +714,11 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
byte[] buffer = new byte[8192]; byte[] buffer = new byte[8192];
while ((entry = zipInput.getNextEntry()) != null) { while ((entry = zipInput.getNextEntry()) != null) {
if (entry.getName().startsWith("elasticsearch/")) { if (entry.getName().startsWith("elasticsearch/")) {
throw new UserException(PLUGIN_MALFORMED, "This plugin was built with an older plugin structure." + throw new UserException(
" Contact the plugin author to remove the intermediate \"elasticsearch\" directory within the plugin zip."); PLUGIN_MALFORMED,
"This plugin was built with an older plugin structure."
+ " Contact the plugin author to remove the intermediate \"elasticsearch\" directory within the plugin zip."
);
} }
Path targetFile = target.resolve(entry.getName()); Path targetFile = target.resolve(entry.getName());
@ -689,8 +728,10 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
// normalizing the path (which removes foo/..) and ensuring the normalized entry // normalizing the path (which removes foo/..) and ensuring the normalized entry
// is still rooted with the target plugin directory. // is still rooted with the target plugin directory.
if (targetFile.normalize().startsWith(target) == false) { if (targetFile.normalize().startsWith(target) == false) {
throw new UserException(PLUGIN_MALFORMED, "Zip contains entry name '" + throw new UserException(
entry.getName() + "' resolving outside of plugin directory"); PLUGIN_MALFORMED,
"Zip contains entry name '" + entry.getName() + "' resolving outside of plugin directory"
);
} }
// be on the safe side: do not rely on that directories are always extracted // be on the safe side: do not rely on that directories are always extracted
@ -725,9 +766,9 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
// and the Jimfs test dependency is upgraded to include // and the Jimfs test dependency is upgraded to include
// this pull request // this pull request
final StackTraceElement[] elements = e.getStackTrace(); final StackTraceElement[] elements = e.getStackTrace();
if (elements.length >= 1 && if (elements.length >= 1
elements[0].getClassName().equals("com.google.common.jimfs.AttributeService") && && elements[0].getClassName().equals("com.google.common.jimfs.AttributeService")
elements[0].getMethodName().equals("setAttributeInternal")) { && elements[0].getMethodName().equals("setAttributeInternal")) {
return stagingDirectoryWithoutPosixPermissions(pluginsDir); return stagingDirectoryWithoutPosixPermissions(pluginsDir);
} else { } else {
throw e; throw e;
@ -753,10 +794,10 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
if (Files.exists(destination)) { if (Files.exists(destination)) {
final String message = String.format( final String message = String.format(
Locale.ROOT, Locale.ROOT,
"plugin directory [%s] already exists; if you need to update the plugin, " + "plugin directory [%s] already exists; if you need to update the plugin, " + "uninstall it first using command 'remove %s'",
"uninstall it first using command 'remove %s'",
destination, destination,
pluginName); pluginName
);
throw new UserException(PLUGIN_EXISTS, message); throw new UserException(PLUGIN_EXISTS, message);
} }
} }
@ -785,24 +826,19 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
private static final String LIB_TOOLS_PLUGIN_CLI_CLASSPATH_JAR; private static final String LIB_TOOLS_PLUGIN_CLI_CLASSPATH_JAR;
static { static {
LIB_TOOLS_PLUGIN_CLI_CLASSPATH_JAR = LIB_TOOLS_PLUGIN_CLI_CLASSPATH_JAR = String.format(Locale.ROOT, ".+%1$slib%1$stools%1$splugin-cli%1$s[^%1$s]+\\.jar", "(/|\\\\)");
String.format(Locale.ROOT, ".+%1$slib%1$stools%1$splugin-cli%1$s[^%1$s]+\\.jar", "(/|\\\\)");
} }
/** check a candidate plugin for jar hell before installing it */ /** check a candidate plugin for jar hell before installing it */
void jarHellCheck(PluginInfo candidateInfo, Path candidateDir, Path pluginsDir, Path modulesDir) throws Exception { void jarHellCheck(PluginInfo candidateInfo, Path candidateDir, Path pluginsDir, Path modulesDir) throws Exception {
// create list of current jars in classpath // create list of current jars in classpath
final Set<URL> classpath = final Set<URL> classpath = JarHell.parseClassPath().stream().filter(url -> {
JarHell.parseClassPath()
.stream()
.filter(url -> {
try { try {
return url.toURI().getPath().matches(LIB_TOOLS_PLUGIN_CLI_CLASSPATH_JAR) == false; return url.toURI().getPath().matches(LIB_TOOLS_PLUGIN_CLI_CLASSPATH_JAR) == false;
} catch (final URISyntaxException e) { } catch (final URISyntaxException e) {
throw new AssertionError(e); throw new AssertionError(e);
} }
}) }).collect(Collectors.toSet());
.collect(Collectors.toSet());
// read existing bundles. this does some checks on the installation too. // read existing bundles. this does some checks on the installation too.
Set<PluginsService.Bundle> bundles = new HashSet<>(PluginsService.getPluginBundles(pluginsDir)); Set<PluginsService.Bundle> bundles = new HashSet<>(PluginsService.getPluginBundles(pluginsDir));
@ -825,8 +861,8 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
* Installs the plugin from {@code tmpRoot} into the plugins dir. * Installs the plugin from {@code tmpRoot} into the plugins dir.
* If the plugin has a bin dir and/or a config dir, those are moved. * If the plugin has a bin dir and/or a config dir, those are moved.
*/ */
private PluginInfo installPlugin(Terminal terminal, boolean isBatch, Path tmpRoot, private PluginInfo installPlugin(Terminal terminal, boolean isBatch, Path tmpRoot, Environment env, List<Path> deleteOnFailure)
Environment env, List<Path> deleteOnFailure) throws Exception { throws Exception {
final PluginInfo info = loadPluginInfo(terminal, tmpRoot, env); final PluginInfo info = loadPluginInfo(terminal, tmpRoot, env);
// read optional security policy (extra permissions), if it exists, confirm or warn the user // read optional security policy (extra permissions), if it exists, confirm or warn the user
Path policy = tmpRoot.resolve(PluginInfo.ES_PLUGIN_POLICY); Path policy = tmpRoot.resolve(PluginInfo.ES_PLUGIN_POLICY);
@ -841,15 +877,20 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
final Path destination = env.pluginsFile().resolve(info.getName()); final Path destination = env.pluginsFile().resolve(info.getName());
deleteOnFailure.add(destination); deleteOnFailure.add(destination);
installPluginSupportFiles(info, tmpRoot, env.binFile().resolve(info.getName()), installPluginSupportFiles(
env.configFile().resolve(info.getName()), deleteOnFailure); info,
tmpRoot,
env.binFile().resolve(info.getName()),
env.configFile().resolve(info.getName()),
deleteOnFailure
);
movePlugin(tmpRoot, destination); movePlugin(tmpRoot, destination);
return info; return info;
} }
/** Moves bin and config directories from the plugin if they exist */ /** Moves bin and config directories from the plugin if they exist */
private void installPluginSupportFiles(PluginInfo info, Path tmpRoot, private void installPluginSupportFiles(PluginInfo info, Path tmpRoot, Path destBinDir, Path destConfigDir, List<Path> deleteOnFailure)
Path destBinDir, Path destConfigDir, List<Path> deleteOnFailure) throws Exception { throws Exception {
Path tmpBinDir = tmpRoot.resolve("bin"); Path tmpBinDir = tmpRoot.resolve("bin");
if (Files.exists(tmpBinDir)) { if (Files.exists(tmpBinDir)) {
deleteOnFailure.add(destBinDir); deleteOnFailure.add(destBinDir);
@ -900,8 +941,10 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(tmpBinDir)) { try (DirectoryStream<Path> stream = Files.newDirectoryStream(tmpBinDir)) {
for (Path srcFile : stream) { for (Path srcFile : stream) {
if (Files.isDirectory(srcFile)) { if (Files.isDirectory(srcFile)) {
throw new UserException(PLUGIN_MALFORMED, "Directories not allowed in bin dir " + throw new UserException(
"for plugin " + info.getName() + ", found " + srcFile.getFileName()); PLUGIN_MALFORMED,
"Directories not allowed in bin dir " + "for plugin " + info.getName() + ", found " + srcFile.getFileName()
);
} }
Path destFile = destBinDir.resolve(tmpBinDir.relativize(srcFile)); Path destFile = destBinDir.resolve(tmpBinDir.relativize(srcFile));
@ -918,16 +961,18 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
*/ */
private void installConfig(PluginInfo info, Path tmpConfigDir, Path destConfigDir) throws Exception { private void installConfig(PluginInfo info, Path tmpConfigDir, Path destConfigDir) throws Exception {
if (Files.isDirectory(tmpConfigDir) == false) { if (Files.isDirectory(tmpConfigDir) == false) {
throw new UserException(PLUGIN_MALFORMED, throw new UserException(PLUGIN_MALFORMED, "config in plugin " + info.getName() + " is not a directory");
"config in plugin " + info.getName() + " is not a directory");
} }
Files.createDirectories(destConfigDir); Files.createDirectories(destConfigDir);
setFileAttributes(destConfigDir, CONFIG_DIR_PERMS); setFileAttributes(destConfigDir, CONFIG_DIR_PERMS);
final PosixFileAttributeView destConfigDirAttributesView = final PosixFileAttributeView destConfigDirAttributesView = Files.getFileAttributeView(
Files.getFileAttributeView(destConfigDir.getParent(), PosixFileAttributeView.class); destConfigDir.getParent(),
final PosixFileAttributes destConfigDirAttributes = PosixFileAttributeView.class
destConfigDirAttributesView != null ? destConfigDirAttributesView.readAttributes() : null; );
final PosixFileAttributes destConfigDirAttributes = destConfigDirAttributesView != null
? destConfigDirAttributesView.readAttributes()
: null;
if (destConfigDirAttributes != null) { if (destConfigDirAttributes != null) {
setOwnerGroup(destConfigDir, destConfigDirAttributes); setOwnerGroup(destConfigDir, destConfigDirAttributes);
} }
@ -935,8 +980,7 @@ class InstallPluginCommand extends EnvironmentAwareCommand {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(tmpConfigDir)) { try (DirectoryStream<Path> stream = Files.newDirectoryStream(tmpConfigDir)) {
for (Path srcFile : stream) { for (Path srcFile : stream) {
if (Files.isDirectory(srcFile)) { if (Files.isDirectory(srcFile)) {
throw new UserException(PLUGIN_MALFORMED, throw new UserException(PLUGIN_MALFORMED, "Directories not allowed in config dir for plugin " + info.getName());
"Directories not allowed in config dir for plugin " + info.getName());
} }
Path destFile = destConfigDir.resolve(tmpConfigDir.relativize(srcFile)); Path destFile = destConfigDir.resolve(tmpConfigDir.relativize(srcFile));

View File

@ -66,8 +66,15 @@ class ListPluginsCommand extends EnvironmentAwareCommand {
PluginInfo info = PluginInfo.readFromProperties(env.pluginsFile().resolve(plugin)); PluginInfo info = PluginInfo.readFromProperties(env.pluginsFile().resolve(plugin));
terminal.println(Terminal.Verbosity.VERBOSE, info.toString(prefix)); terminal.println(Terminal.Verbosity.VERBOSE, info.toString(prefix));
if (info.getElasticsearchVersion().equals(Version.CURRENT) == false) { if (info.getElasticsearchVersion().equals(Version.CURRENT) == false) {
terminal.errorPrintln("WARNING: plugin [" + info.getName() + "] was built for Elasticsearch version " + info.getVersion() + terminal.errorPrintln(
" but version " + Version.CURRENT + " is required"); "WARNING: plugin ["
+ info.getName()
+ "] was built for Elasticsearch version "
+ info.getVersion()
+ " but version "
+ Version.CURRENT
+ " is required"
);
} }
} }
} }

View File

@ -71,7 +71,7 @@ abstract class ProgressInputStream extends FilterInputStream {
count += byteCount; count += byteCount;
// rounding up to 100% would mean we say we are done, before we are... // rounding up to 100% would mean we say we are done, before we are...
// this also catches issues, when expectedTotalSize was guessed wrong // this also catches issues, when expectedTotalSize was guessed wrong
int percent = Math.min(99, (int) Math.floor(100.0*count/expectedTotalSize)); int percent = Math.min(99, (int) Math.floor(100.0 * count / expectedTotalSize));
if (percent > currentPercent) { if (percent > currentPercent) {
currentPercent = percent; currentPercent = percent;
onProgress(percent); onProgress(percent);

View File

@ -95,8 +95,10 @@ class RemovePluginCommand extends EnvironmentAwareCommand {
} }
} }
if (usedBy.isEmpty() == false) { if (usedBy.isEmpty() == false) {
throw new UserException(PLUGIN_STILL_USED, "plugin [" + pluginName + "] cannot be removed" + throw new UserException(
" because it is extended by other plugins: " + usedBy); PLUGIN_STILL_USED,
"plugin [" + pluginName + "] cannot be removed" + " because it is extended by other plugins: " + usedBy
);
} }
final Path pluginDir = env.pluginsFile().resolve(pluginName); final Path pluginDir = env.pluginsFile().resolve(pluginName);
@ -112,7 +114,10 @@ class RemovePluginCommand extends EnvironmentAwareCommand {
if ((!Files.exists(pluginDir) && !Files.exists(pluginConfigDir) && !Files.exists(removing)) if ((!Files.exists(pluginDir) && !Files.exists(pluginConfigDir) && !Files.exists(removing))
|| (!Files.exists(pluginDir) && Files.exists(pluginConfigDir) && !purge)) { || (!Files.exists(pluginDir) && Files.exists(pluginConfigDir) && !purge)) {
final String message = String.format( final String message = String.format(
Locale.ROOT, "plugin [%s] not found; run 'elasticsearch-plugin list' to get list of installed plugins", pluginName); Locale.ROOT,
"plugin [%s] not found; run 'elasticsearch-plugin list' to get list of installed plugins",
pluginName
);
throw new UserException(ExitCodes.CONFIG, message); throw new UserException(ExitCodes.CONFIG, message);
} }
@ -156,7 +161,8 @@ class RemovePluginCommand extends EnvironmentAwareCommand {
final String message = String.format( final String message = String.format(
Locale.ROOT, Locale.ROOT,
"-> preserving plugin config files [%s] in case of upgrade; use --purge if not needed", "-> preserving plugin config files [%s] in case of upgrade; use --purge if not needed",
pluginConfigDir); pluginConfigDir
);
terminal.println(message); terminal.println(message);
} }
} }

View File

@ -191,7 +191,7 @@ public class InstallPluginCommandTests extends ESTestCase {
parameters.add(new Parameter(Jimfs.newFileSystem(Configuration.windows()), "c:\\")); parameters.add(new Parameter(Jimfs.newFileSystem(Configuration.windows()), "c:\\"));
parameters.add(new Parameter(Jimfs.newFileSystem(toPosix(Configuration.osX())), "/")); parameters.add(new Parameter(Jimfs.newFileSystem(toPosix(Configuration.osX())), "/"));
parameters.add(new Parameter(Jimfs.newFileSystem(toPosix(Configuration.unix())), "/")); parameters.add(new Parameter(Jimfs.newFileSystem(toPosix(Configuration.unix())), "/"));
parameters.add(new Parameter(PathUtils.getDefaultFileSystem(), LuceneTestCase::createTempDir )); parameters.add(new Parameter(PathUtils.getDefaultFileSystem(), LuceneTestCase::createTempDir));
return parameters.stream().map(p -> new Object[] { p.fileSystem, p.temp }).collect(Collectors.toList()); return parameters.stream().map(p -> new Object[] { p.fileSystem, p.temp }).collect(Collectors.toList());
} }
@ -208,9 +208,7 @@ public class InstallPluginCommandTests extends ESTestCase {
Files.createFile(home.resolve("config").resolve("elasticsearch.yml")); Files.createFile(home.resolve("config").resolve("elasticsearch.yml"));
Path plugins = Files.createDirectories(home.resolve("plugins")); Path plugins = Files.createDirectories(home.resolve("plugins"));
assertTrue(Files.exists(plugins)); assertTrue(Files.exists(plugins));
Settings settings = Settings.builder() Settings settings = Settings.builder().put("path.home", home).build();
.put("path.home", home)
.build();
return Tuple.tuple(home, TestEnvironment.newEnvironment(settings)); return Tuple.tuple(home, TestEnvironment.newEnvironment(settings));
} }
@ -249,14 +247,23 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
static void writePlugin(String name, Path structure, String... additionalProps) throws IOException { static void writePlugin(String name, Path structure, String... additionalProps) throws IOException {
String[] properties = Stream.concat(Stream.of( String[] properties = Stream.concat(
"description", "fake desc", Stream.of(
"name", name, "description",
"version", "1.0", "fake desc",
"elasticsearch.version", Version.CURRENT.toString(), "name",
"java.version", System.getProperty("java.specification.version"), name,
"classname", "FakePlugin" "version",
), Arrays.stream(additionalProps)).toArray(String[]::new); "1.0",
"elasticsearch.version",
Version.CURRENT.toString(),
"java.version",
System.getProperty("java.specification.version"),
"classname",
"FakePlugin"
),
Arrays.stream(additionalProps)
).toArray(String[]::new);
PluginTestUtil.writePluginProperties(structure, properties); PluginTestUtil.writePluginProperties(structure, properties);
String className = name.substring(0, 1).toUpperCase(Locale.ENGLISH) + name.substring(1) + "Plugin"; String className = name.substring(0, 1).toUpperCase(Locale.ENGLISH) + name.substring(1) + "Plugin";
writeJar(structure.resolve("plugin.jar"), className); writeJar(structure.resolve("plugin.jar"), className);
@ -316,7 +323,9 @@ public class InstallPluginCommandTests extends ESTestCase {
PosixFilePermission.GROUP_READ, PosixFilePermission.GROUP_READ,
PosixFilePermission.GROUP_EXECUTE, PosixFilePermission.GROUP_EXECUTE,
PosixFilePermission.OTHERS_READ, PosixFilePermission.OTHERS_READ,
PosixFilePermission.OTHERS_EXECUTE)); PosixFilePermission.OTHERS_EXECUTE
)
);
} }
assertTrue("jar was copied", Files.exists(got.resolve("plugin.jar"))); assertTrue("jar was copied", Files.exists(got.resolve("plugin.jar")));
assertFalse("bin was not copied", Files.exists(got.resolve("bin"))); assertFalse("bin was not copied", Files.exists(got.resolve("bin")));
@ -351,8 +360,8 @@ public class InstallPluginCommandTests extends ESTestCase {
GroupPrincipal group = null; GroupPrincipal group = null;
if (isPosix) { if (isPosix) {
PosixFileAttributes configAttributes = PosixFileAttributes configAttributes = Files.getFileAttributeView(env.configFile(), PosixFileAttributeView.class)
Files.getFileAttributeView(env.configFile(), PosixFileAttributeView.class).readAttributes(); .readAttributes();
user = configAttributes.owner(); user = configAttributes.owner();
group = configAttributes.group(); group = configAttributes.group();
@ -427,7 +436,8 @@ public class InstallPluginCommandTests extends ESTestCase {
String pluginZip = createPluginUrl("fake", pluginDir); String pluginZip = createPluginUrl("fake", pluginDir);
final FileNotFoundException e = expectThrows( final FileNotFoundException e = expectThrows(
FileNotFoundException.class, FileNotFoundException.class,
() -> installPlugins(Arrays.asList(pluginZip, pluginZip + "does-not-exist"), env.v1())); () -> installPlugins(Arrays.asList(pluginZip, pluginZip + "does-not-exist"), env.v1())
);
assertThat(e, hasToString(containsString("does-not-exist"))); assertThat(e, hasToString(containsString("does-not-exist")));
final Path fakeInstallPath = env.v2().pluginsFile().resolve("fake"); final Path fakeInstallPath = env.v2().pluginsFile().resolve("fake");
// fake should have been removed when the file not found exception occurred // fake should have been removed when the file not found exception occurred
@ -445,7 +455,8 @@ public class InstallPluginCommandTests extends ESTestCase {
final String expected = String.format( final String expected = String.format(
Locale.ROOT, Locale.ROOT,
"found file [%s] from a failed attempt to remove the plugin [failed]; execute [elasticsearch-plugin remove failed]", "found file [%s] from a failed attempt to remove the plugin [failed]; execute [elasticsearch-plugin remove failed]",
removing); removing
);
assertThat(e, hasToString(containsString(expected))); assertThat(e, hasToString(containsString(expected)));
} }
@ -471,9 +482,11 @@ public class InstallPluginCommandTests extends ESTestCase {
public void testFileNotMaven() throws Exception { public void testFileNotMaven() throws Exception {
Tuple<Path, Environment> env = createEnv(fs, temp); Tuple<Path, Environment> env = createEnv(fs, temp);
String dir = randomAlphaOfLength(10) + ":" + randomAlphaOfLength(5) + "\\" + randomAlphaOfLength(5); String dir = randomAlphaOfLength(10) + ":" + randomAlphaOfLength(5) + "\\" + randomAlphaOfLength(5);
Exception e = expectThrows(Exception.class, Exception e = expectThrows(
Exception.class,
// has two colons, so it appears similar to maven coordinates // has two colons, so it appears similar to maven coordinates
() -> installPlugin("file:" + dir, env.v1())); () -> installPlugin("file:" + dir, env.v1())
);
assertFalse(e.getMessage(), e.getMessage().contains("maven.org")); assertFalse(e.getMessage(), e.getMessage().contains("maven.org"));
assertTrue(e.getMessage(), e.getMessage().contains(dir)); assertTrue(e.getMessage(), e.getMessage().contains(dir));
} }
@ -522,8 +535,10 @@ public class InstallPluginCommandTests extends ESTestCase {
Path pluginDirectory = createPluginDir(temp); Path pluginDirectory = createPluginDir(temp);
writeJar(pluginDirectory.resolve("other.jar"), "FakePlugin"); writeJar(pluginDirectory.resolve("other.jar"), "FakePlugin");
String pluginZip = createPluginUrl("fake", pluginDirectory); // adds plugin.jar with FakePlugin String pluginZip = createPluginUrl("fake", pluginDirectory); // adds plugin.jar with FakePlugin
IllegalStateException e = expectThrows(IllegalStateException.class, IllegalStateException e = expectThrows(
() -> installPlugin(pluginZip, environment.v1(), defaultCommand)); IllegalStateException.class,
() -> installPlugin(pluginZip, environment.v1(), defaultCommand)
);
assertTrue(e.getMessage(), e.getMessage().contains("jar hell")); assertTrue(e.getMessage(), e.getMessage().contains("jar hell"));
assertInstallCleaned(environment.v2()); assertInstallCleaned(environment.v2());
} }
@ -797,12 +812,13 @@ public class InstallPluginCommandTests extends ESTestCase {
runInstallXPackTest( runInstallXPackTest(
Build.Flavor.OSS, Build.Flavor.OSS,
UserException.class, UserException.class,
"X-Pack is not available with the oss distribution; to use X-Pack features use the default distribution"); "X-Pack is not available with the oss distribution; to use X-Pack features use the default distribution"
);
runInstallXPackTest(Build.Flavor.UNKNOWN, IllegalStateException.class, "your distribution is broken"); runInstallXPackTest(Build.Flavor.UNKNOWN, IllegalStateException.class, "your distribution is broken");
} }
private <T extends Exception> void runInstallXPackTest( private <T extends Exception> void runInstallXPackTest(final Build.Flavor flavor, final Class<T> clazz, final String expectedMessage)
final Build.Flavor flavor, final Class<T> clazz, final String expectedMessage) throws IOException { throws IOException {
final InstallPluginCommand flavorCommand = new InstallPluginCommand() { final InstallPluginCommand flavorCommand = new InstallPluginCommand() {
@Override @Override
Build.Flavor buildFlavor() { Build.Flavor buildFlavor() {
@ -811,8 +827,10 @@ public class InstallPluginCommandTests extends ESTestCase {
}; };
final Environment environment = createEnv(fs, temp).v2(); final Environment environment = createEnv(fs, temp).v2();
final T exception = final T exception = expectThrows(
expectThrows(clazz, () -> flavorCommand.execute(terminal, Collections.singletonList("x-pack"), false, environment)); clazz,
() -> flavorCommand.execute(terminal, Collections.singletonList("x-pack"), false, environment)
);
assertThat(exception, hasToString(containsString(expectedMessage))); assertThat(exception, hasToString(containsString(expectedMessage)));
} }
@ -857,12 +875,19 @@ public class InstallPluginCommandTests extends ESTestCase {
Path pluginDir = createPluginDir(temp); Path pluginDir = createPluginDir(temp);
String pluginZip = createPluginUrl("fake", pluginDir); String pluginZip = createPluginUrl("fake", pluginDir);
installPlugin(pluginZip, env.v1()); installPlugin(pluginZip, env.v1());
final UserException e = expectThrows(UserException.class, final UserException e = expectThrows(
() -> installPlugin(pluginZip, env.v1(), randomFrom(skipJarHellCommand, defaultCommand))); UserException.class,
() -> installPlugin(pluginZip, env.v1(), randomFrom(skipJarHellCommand, defaultCommand))
);
assertThat( assertThat(
e.getMessage(), e.getMessage(),
equalTo("plugin directory [" + env.v2().pluginsFile().resolve("fake") + "] already exists; " + equalTo(
"if you need to update the plugin, uninstall it first using command 'remove fake'")); "plugin directory ["
+ env.v2().pluginsFile().resolve("fake")
+ "] already exists; "
+ "if you need to update the plugin, uninstall it first using command 'remove fake'"
)
);
} }
private void installPlugin(MockTerminal terminal, boolean isBatch) throws Exception { private void installPlugin(MockTerminal terminal, boolean isBatch) throws Exception {
@ -885,7 +910,8 @@ public class InstallPluginCommandTests extends ESTestCase {
final String shaExtension, final String shaExtension,
final Function<byte[], String> shaCalculator, final Function<byte[], String> shaCalculator,
final PGPSecretKey secretKey, final PGPSecretKey secretKey,
final BiFunction<byte[], PGPSecretKey, String> signature) throws Exception { final BiFunction<byte[], PGPSecretKey, String> signature
) throws Exception {
Tuple<Path, Environment> env = createEnv(fs, temp); Tuple<Path, Environment> env = createEnv(fs, temp);
Path pluginDir = createPluginDir(temp); Path pluginDir = createPluginDir(temp);
Path pluginZip = createPlugin(name, pluginDir); Path pluginZip = createPlugin(name, pluginDir);
@ -897,6 +923,7 @@ public class InstallPluginCommandTests extends ESTestCase {
Files.copy(pluginZip, downloadedPath); Files.copy(pluginZip, downloadedPath);
return downloadedPath; return downloadedPath;
} }
@Override @Override
URL openUrl(String urlString) throws IOException { URL openUrl(String urlString) throws IOException {
if ((url + shaExtension).equals(urlString)) { if ((url + shaExtension).equals(urlString)) {
@ -952,6 +979,7 @@ public class InstallPluginCommandTests extends ESTestCase {
boolean urlExists(Terminal terminal, String urlString) throws IOException { boolean urlExists(Terminal terminal, String urlString) throws IOException {
return urlString.equals(url); return urlString.equals(url);
} }
@Override @Override
String getStagingHash() { String getStagingHash() {
return stagingHash; return stagingHash;
@ -972,15 +1000,30 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void assertInstallPluginFromUrl( public void assertInstallPluginFromUrl(
final String pluginId, final String name, final String url, final String stagingHash, boolean isSnapshot) throws Exception { final String pluginId,
final String name,
final String url,
final String stagingHash,
boolean isSnapshot
) throws Exception {
final MessageDigest digest = MessageDigest.getInstance("SHA-512"); final MessageDigest digest = MessageDigest.getInstance("SHA-512");
assertInstallPluginFromUrl( assertInstallPluginFromUrl(
pluginId, name, url, stagingHash, isSnapshot, ".sha512", checksumAndFilename(digest, url), newSecretKey(), this::signature); pluginId,
name,
url,
stagingHash,
isSnapshot,
".sha512",
checksumAndFilename(digest, url),
newSecretKey(),
this::signature
);
} }
public void testOfficialPlugin() throws Exception { public void testOfficialPlugin() throws Exception {
String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-" + String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-"
Build.CURRENT.getQualifiedVersion() + ".zip"; + Build.CURRENT.getQualifiedVersion()
+ ".zip";
assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, null, false); assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, null, false);
} }
@ -989,7 +1032,8 @@ public class InstallPluginCommandTests extends ESTestCase {
Locale.ROOT, Locale.ROOT,
"https://snapshots.elastic.co/%s-abc123/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-%s.zip", "https://snapshots.elastic.co/%s-abc123/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-%s.zip",
Version.CURRENT, Version.CURRENT,
Build.CURRENT.getQualifiedVersion()); Build.CURRENT.getQualifiedVersion()
);
assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, "abc123", true); assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, "abc123", true);
} }
@ -998,24 +1042,35 @@ public class InstallPluginCommandTests extends ESTestCase {
Locale.ROOT, Locale.ROOT,
"https://snapshots.elastic.co/%s-abc123/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-%s.zip", "https://snapshots.elastic.co/%s-abc123/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-%s.zip",
Version.CURRENT, Version.CURRENT,
Build.CURRENT.getQualifiedVersion()); Build.CURRENT.getQualifiedVersion()
);
// attemping to install a release build of a plugin (no staging ID) on a snapshot build should throw a user exception // attemping to install a release build of a plugin (no staging ID) on a snapshot build should throw a user exception
final UserException e = final UserException e = expectThrows(
expectThrows(UserException.class, () -> assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, null, true)); UserException.class,
() -> assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, null, true)
);
assertThat(e.exitCode, equalTo(ExitCodes.CONFIG)); assertThat(e.exitCode, equalTo(ExitCodes.CONFIG));
assertThat( assertThat(
e, hasToString(containsString("attempted to install release build of official plugin on snapshot build of Elasticsearch"))); e,
hasToString(containsString("attempted to install release build of official plugin on snapshot build of Elasticsearch"))
);
} }
public void testOfficialPluginStaging() throws Exception { public void testOfficialPluginStaging() throws Exception {
String url = "https://staging.elastic.co/" + Version.CURRENT + "-abc123/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-" String url = "https://staging.elastic.co/"
+ Build.CURRENT.getQualifiedVersion() + ".zip"; + Version.CURRENT
+ "-abc123/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-"
+ Build.CURRENT.getQualifiedVersion()
+ ".zip";
assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, "abc123", false); assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, "abc123", false);
} }
public void testOfficialPlatformPlugin() throws Exception { public void testOfficialPlatformPlugin() throws Exception {
String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-" + Platforms.PLATFORM_NAME + String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-"
"-" + Build.CURRENT.getQualifiedVersion() + ".zip"; + Platforms.PLATFORM_NAME
+ "-"
+ Build.CURRENT.getQualifiedVersion()
+ ".zip";
assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, null, false); assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, null, false);
} }
@ -1025,13 +1080,19 @@ public class InstallPluginCommandTests extends ESTestCase {
"https://snapshots.elastic.co/%s-abc123/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-%s-%s.zip", "https://snapshots.elastic.co/%s-abc123/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-%s-%s.zip",
Version.CURRENT, Version.CURRENT,
Platforms.PLATFORM_NAME, Platforms.PLATFORM_NAME,
Build.CURRENT.getQualifiedVersion()); Build.CURRENT.getQualifiedVersion()
);
assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, "abc123", true); assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, "abc123", true);
} }
public void testOfficialPlatformPluginStaging() throws Exception { public void testOfficialPlatformPluginStaging() throws Exception {
String url = "https://staging.elastic.co/" + Version.CURRENT + "-abc123/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-" String url = "https://staging.elastic.co/"
+ Platforms.PLATFORM_NAME + "-"+ Build.CURRENT.getQualifiedVersion() + ".zip"; + Version.CURRENT
+ "-abc123/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-"
+ Platforms.PLATFORM_NAME
+ "-"
+ Build.CURRENT.getQualifiedVersion()
+ ".zip";
assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, "abc123", false); assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, "abc123", false);
} }
@ -1053,12 +1114,23 @@ public class InstallPluginCommandTests extends ESTestCase {
} }
public void testOfficialShaMissing() throws Exception { public void testOfficialShaMissing() throws Exception {
String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-" + String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-"
Build.CURRENT.getQualifiedVersion() + ".zip"; + Build.CURRENT.getQualifiedVersion()
+ ".zip";
MessageDigest digest = MessageDigest.getInstance("SHA-1"); MessageDigest digest = MessageDigest.getInstance("SHA-1");
UserException e = expectThrows(UserException.class, () -> UserException e = expectThrows(
assertInstallPluginFromUrl("analysis-icu", "analysis-icu", url, null, false, UserException.class,
".sha1", checksum(digest), null, (b, p) -> null) () -> assertInstallPluginFromUrl(
"analysis-icu",
"analysis-icu",
url,
null,
false,
".sha1",
checksum(digest),
null,
(b, p) -> null
)
); );
assertEquals(ExitCodes.IO_ERROR, e.exitCode); assertEquals(ExitCodes.IO_ERROR, e.exitCode);
assertEquals("Plugin checksum missing: " + url + ".sha512", e.getMessage()); assertEquals("Plugin checksum missing: " + url + ".sha512", e.getMessage());
@ -1066,30 +1138,55 @@ public class InstallPluginCommandTests extends ESTestCase {
public void testMavenShaMissing() throws Exception { public void testMavenShaMissing() throws Exception {
String url = "https://repo1.maven.org/maven2/mygroup/myplugin/1.0.0/myplugin-1.0.0.zip"; String url = "https://repo1.maven.org/maven2/mygroup/myplugin/1.0.0/myplugin-1.0.0.zip";
UserException e = expectThrows(UserException.class, () -> UserException e = expectThrows(
assertInstallPluginFromUrl( UserException.class,
"mygroup:myplugin:1.0.0", "myplugin", url, null, false, ".dne", bytes -> null, null, (b, p) -> null)); () -> assertInstallPluginFromUrl(
"mygroup:myplugin:1.0.0",
"myplugin",
url,
null,
false,
".dne",
bytes -> null,
null,
(b, p) -> null
)
);
assertEquals(ExitCodes.IO_ERROR, e.exitCode); assertEquals(ExitCodes.IO_ERROR, e.exitCode);
assertEquals("Plugin checksum missing: " + url + ".sha1", e.getMessage()); assertEquals("Plugin checksum missing: " + url + ".sha1", e.getMessage());
} }
public void testInvalidShaFileMissingFilename() throws Exception { public void testInvalidShaFileMissingFilename() throws Exception {
String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-" + String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-"
Build.CURRENT.getQualifiedVersion() + ".zip"; + Build.CURRENT.getQualifiedVersion()
+ ".zip";
MessageDigest digest = MessageDigest.getInstance("SHA-512"); MessageDigest digest = MessageDigest.getInstance("SHA-512");
UserException e = expectThrows(UserException.class, UserException e = expectThrows(
UserException.class,
() -> assertInstallPluginFromUrl( () -> assertInstallPluginFromUrl(
"analysis-icu", "analysis-icu", url, null, false, ".sha512", checksum(digest), null, (b, p) -> null)); "analysis-icu",
"analysis-icu",
url,
null,
false,
".sha512",
checksum(digest),
null,
(b, p) -> null
)
);
assertEquals(ExitCodes.IO_ERROR, e.exitCode); assertEquals(ExitCodes.IO_ERROR, e.exitCode);
assertTrue(e.getMessage(), e.getMessage().startsWith("Invalid checksum file")); assertTrue(e.getMessage(), e.getMessage().startsWith("Invalid checksum file"));
} }
public void testInvalidShaFileMismatchFilename() throws Exception { public void testInvalidShaFileMismatchFilename() throws Exception {
String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-" + String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-"
Build.CURRENT.getQualifiedVersion()+ ".zip"; + Build.CURRENT.getQualifiedVersion()
+ ".zip";
MessageDigest digest = MessageDigest.getInstance("SHA-512"); MessageDigest digest = MessageDigest.getInstance("SHA-512");
UserException e = expectThrows(UserException.class, () -> UserException e = expectThrows(
assertInstallPluginFromUrl( UserException.class,
() -> assertInstallPluginFromUrl(
"analysis-icu", "analysis-icu",
"analysis-icu", "analysis-icu",
url, url,
@ -1098,17 +1195,21 @@ public class InstallPluginCommandTests extends ESTestCase {
".sha512", ".sha512",
checksumAndString(digest, " repository-s3-" + Build.CURRENT.getQualifiedVersion() + ".zip"), checksumAndString(digest, " repository-s3-" + Build.CURRENT.getQualifiedVersion() + ".zip"),
null, null,
(b, p) -> null)); (b, p) -> null
)
);
assertEquals(ExitCodes.IO_ERROR, e.exitCode); assertEquals(ExitCodes.IO_ERROR, e.exitCode);
assertThat(e, hasToString(matches("checksum file at \\[.*\\] is not for this plugin"))); assertThat(e, hasToString(matches("checksum file at \\[.*\\] is not for this plugin")));
} }
public void testInvalidShaFileContainingExtraLine() throws Exception { public void testInvalidShaFileContainingExtraLine() throws Exception {
String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-" + String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-"
Build.CURRENT.getQualifiedVersion() + ".zip"; + Build.CURRENT.getQualifiedVersion()
+ ".zip";
MessageDigest digest = MessageDigest.getInstance("SHA-512"); MessageDigest digest = MessageDigest.getInstance("SHA-512");
UserException e = expectThrows(UserException.class, () -> UserException e = expectThrows(
assertInstallPluginFromUrl( UserException.class,
() -> assertInstallPluginFromUrl(
"analysis-icu", "analysis-icu",
"analysis-icu", "analysis-icu",
url, url,
@ -1117,16 +1218,20 @@ public class InstallPluginCommandTests extends ESTestCase {
".sha512", ".sha512",
checksumAndString(digest, " analysis-icu-" + Build.CURRENT.getQualifiedVersion() + ".zip\nfoobar"), checksumAndString(digest, " analysis-icu-" + Build.CURRENT.getQualifiedVersion() + ".zip\nfoobar"),
null, null,
(b, p) -> null)); (b, p) -> null
)
);
assertEquals(ExitCodes.IO_ERROR, e.exitCode); assertEquals(ExitCodes.IO_ERROR, e.exitCode);
assertTrue(e.getMessage(), e.getMessage().startsWith("Invalid checksum file")); assertTrue(e.getMessage(), e.getMessage().startsWith("Invalid checksum file"));
} }
public void testSha512Mismatch() throws Exception { public void testSha512Mismatch() throws Exception {
String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-" + String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-"
Build.CURRENT.getQualifiedVersion() + ".zip"; + Build.CURRENT.getQualifiedVersion()
UserException e = expectThrows(UserException.class, () -> + ".zip";
assertInstallPluginFromUrl( UserException e = expectThrows(
UserException.class,
() -> assertInstallPluginFromUrl(
"analysis-icu", "analysis-icu",
"analysis-icu", "analysis-icu",
url, url,
@ -1135,25 +1240,40 @@ public class InstallPluginCommandTests extends ESTestCase {
".sha512", ".sha512",
bytes -> "foobar analysis-icu-" + Build.CURRENT.getQualifiedVersion() + ".zip", bytes -> "foobar analysis-icu-" + Build.CURRENT.getQualifiedVersion() + ".zip",
null, null,
(b, p) -> null)); (b, p) -> null
)
);
assertEquals(ExitCodes.IO_ERROR, e.exitCode); assertEquals(ExitCodes.IO_ERROR, e.exitCode);
assertTrue(e.getMessage(), e.getMessage().contains("SHA-512 mismatch, expected foobar")); assertTrue(e.getMessage(), e.getMessage().contains("SHA-512 mismatch, expected foobar"));
} }
public void testSha1Mismatch() throws Exception { public void testSha1Mismatch() throws Exception {
String url = "https://repo1.maven.org/maven2/mygroup/myplugin/1.0.0/myplugin-1.0.0.zip"; String url = "https://repo1.maven.org/maven2/mygroup/myplugin/1.0.0/myplugin-1.0.0.zip";
UserException e = expectThrows(UserException.class, () -> UserException e = expectThrows(
assertInstallPluginFromUrl( UserException.class,
"mygroup:myplugin:1.0.0", "myplugin", url, null, false, ".sha1", bytes -> "foobar", null, (b, p) -> null)); () -> assertInstallPluginFromUrl(
"mygroup:myplugin:1.0.0",
"myplugin",
url,
null,
false,
".sha1",
bytes -> "foobar",
null,
(b, p) -> null
)
);
assertEquals(ExitCodes.IO_ERROR, e.exitCode); assertEquals(ExitCodes.IO_ERROR, e.exitCode);
assertTrue(e.getMessage(), e.getMessage().contains("SHA-1 mismatch, expected foobar")); assertTrue(e.getMessage(), e.getMessage().contains("SHA-1 mismatch, expected foobar"));
} }
public void testPublicKeyIdMismatchToExpectedPublicKeyId() throws Exception { public void testPublicKeyIdMismatchToExpectedPublicKeyId() throws Exception {
final String icu = "analysis-icu"; final String icu = "analysis-icu";
final String url = final String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/"
"https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/" + icu + "-" + + icu
Build.CURRENT.getQualifiedVersion() + ".zip"; + "-"
+ Build.CURRENT.getQualifiedVersion()
+ ".zip";
final MessageDigest digest = MessageDigest.getInstance("SHA-512"); final MessageDigest digest = MessageDigest.getInstance("SHA-512");
/* /*
* To setup a situation where the expected public key ID does not match the public key ID used for signing, we generate a new public * To setup a situation where the expected public key ID does not match the public key ID used for signing, we generate a new public
@ -1167,17 +1287,28 @@ public class InstallPluginCommandTests extends ESTestCase {
final String expectedID = Long.toHexString(verifyingKey.getKeyID()).toUpperCase(Locale.ROOT); final String expectedID = Long.toHexString(verifyingKey.getKeyID()).toUpperCase(Locale.ROOT);
final IllegalStateException e = expectThrows( final IllegalStateException e = expectThrows(
IllegalStateException.class, IllegalStateException.class,
() -> () -> assertInstallPluginFromUrl(
assertInstallPluginFromUrl( icu,
icu, icu, url, null, false, ".sha512", checksumAndFilename(digest, url), verifyingKey, signature)); icu,
url,
null,
false,
".sha512",
checksumAndFilename(digest, url),
verifyingKey,
signature
)
);
assertThat(e, hasToString(containsString("key id [" + actualID + "] does not match expected key id [" + expectedID + "]"))); assertThat(e, hasToString(containsString("key id [" + actualID + "] does not match expected key id [" + expectedID + "]")));
} }
public void testFailedSignatureVerification() throws Exception { public void testFailedSignatureVerification() throws Exception {
final String icu = "analysis-icu"; final String icu = "analysis-icu";
final String url = final String url = "https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/"
"https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/" + icu + "-" + + icu
Build.CURRENT.getQualifiedVersion() + ".zip"; + "-"
+ Build.CURRENT.getQualifiedVersion()
+ ".zip";
final MessageDigest digest = MessageDigest.getInstance("SHA-512"); final MessageDigest digest = MessageDigest.getInstance("SHA-512");
/* /*
* To setup a situation where signature verification fails, we will mutate the input byte array by modifying a single byte to some * To setup a situation where signature verification fails, we will mutate the input byte array by modifying a single byte to some
@ -1191,9 +1322,18 @@ public class InstallPluginCommandTests extends ESTestCase {
}; };
final IllegalStateException e = expectThrows( final IllegalStateException e = expectThrows(
IllegalStateException.class, IllegalStateException.class,
() -> () -> assertInstallPluginFromUrl(
assertInstallPluginFromUrl( icu,
icu, icu, url, null, false, ".sha512", checksumAndFilename(digest, url), newSecretKey(), signature)); icu,
url,
null,
false,
".sha512",
checksumAndFilename(digest, url),
newSecretKey(),
signature
)
);
assertThat(e, hasToString(equalTo("java.lang.IllegalStateException: signature verification for [" + url + "] failed"))); assertThat(e, hasToString(equalTo("java.lang.IllegalStateException: signature verification for [" + url + "] failed")));
} }
@ -1211,9 +1351,9 @@ public class InstallPluginCommandTests extends ESTestCase {
null, null,
null, null,
new JcaPGPContentSignerBuilder(pkp.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA256), new JcaPGPContentSignerBuilder(pkp.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA256),
new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_192, sha1Calc) new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_192, sha1Calc).setProvider(new BouncyCastleFipsProvider())
.setProvider(new BouncyCastleFipsProvider()) .build("passphrase".toCharArray())
.build("passphrase".toCharArray())); );
} }
private Function<byte[], String> checksum(final MessageDigest digest) { private Function<byte[], String> checksum(final MessageDigest digest) {
@ -1231,17 +1371,18 @@ public class InstallPluginCommandTests extends ESTestCase {
private String signature(final byte[] bytes, final PGPSecretKey secretKey) { private String signature(final byte[] bytes, final PGPSecretKey secretKey) {
try { try {
final PGPPrivateKey privateKey final PGPPrivateKey privateKey = secretKey.extractPrivateKey(
= secretKey.extractPrivateKey( new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder().build()).build("passphrase".toCharArray())
new JcePBESecretKeyDecryptorBuilder( );
new JcaPGPDigestCalculatorProviderBuilder().build()).build("passphrase".toCharArray())); final PGPSignatureGenerator generator = new PGPSignatureGenerator(
final PGPSignatureGenerator generator = new JcaPGPContentSignerBuilder(privateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512)
new PGPSignatureGenerator( );
new JcaPGPContentSignerBuilder(privateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512));
generator.init(PGPSignature.BINARY_DOCUMENT, privateKey); generator.init(PGPSignature.BINARY_DOCUMENT, privateKey);
final ByteArrayOutputStream output = new ByteArrayOutputStream(); final ByteArrayOutputStream output = new ByteArrayOutputStream();
try (BCPGOutputStream pout = new BCPGOutputStream(new ArmoredOutputStream(output)); try (
InputStream is = new ByteArrayInputStream(bytes)) { BCPGOutputStream pout = new BCPGOutputStream(new ArmoredOutputStream(output));
InputStream is = new ByteArrayInputStream(bytes)
) {
final byte[] buffer = new byte[1024]; final byte[] buffer = new byte[1024];
int read; int read;
while ((read = is.read(buffer)) != -1) { while ((read = is.read(buffer)) != -1) {

View File

@ -19,7 +19,6 @@
package org.elasticsearch.plugins; package org.elasticsearch.plugins;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.NoSuchFileException; import java.nio.file.NoSuchFileException;
@ -50,9 +49,7 @@ public class ListPluginsCommandTests extends ESTestCase {
super.setUp(); super.setUp();
home = createTempDir(); home = createTempDir();
Files.createDirectories(home.resolve("plugins")); Files.createDirectories(home.resolve("plugins"));
Settings settings = Settings.builder() Settings settings = Settings.builder().put("path.home", home).build();
.put("path.home", home)
.build();
env = TestEnvironment.newEnvironment(settings); env = TestEnvironment.newEnvironment(settings);
} }
@ -69,7 +66,7 @@ public class ListPluginsCommandTests extends ESTestCase {
@Override @Override
protected Environment createEnv(Map<String, String> settings) throws UserException { protected Environment createEnv(Map<String, String> settings) throws UserException {
Settings.Builder builder = Settings.builder().put("path.home", home); Settings.Builder builder = Settings.builder().put("path.home", home);
settings.forEach((k,v) -> builder.put(k, v)); settings.forEach((k, v) -> builder.put(k, v));
final Settings realSettings = builder.build(); final Settings realSettings = builder.build();
return new Environment(realSettings, home.resolve("config")); return new Environment(realSettings, home.resolve("config"));
} }
@ -83,15 +80,12 @@ public class ListPluginsCommandTests extends ESTestCase {
return terminal; return terminal;
} }
private static String buildMultiline(String... args){ private static String buildMultiline(String... args) {
return Arrays.stream(args).collect(Collectors.joining("\n", "", "\n")); return Arrays.stream(args).collect(Collectors.joining("\n", "", "\n"));
} }
private static void buildFakePlugin( private static void buildFakePlugin(final Environment env, final String description, final String name, final String classname)
final Environment env, throws IOException {
final String description,
final String name,
final String classname) throws IOException {
buildFakePlugin(env, description, name, classname, false); buildFakePlugin(env, description, name, classname, false);
} }
@ -100,16 +94,25 @@ public class ListPluginsCommandTests extends ESTestCase {
final String description, final String description,
final String name, final String name,
final String classname, final String classname,
final boolean hasNativeController) throws IOException { final boolean hasNativeController
) throws IOException {
PluginTestUtil.writePluginProperties( PluginTestUtil.writePluginProperties(
env.pluginsFile().resolve(name), env.pluginsFile().resolve(name),
"description", description, "description",
"name", name, description,
"version", "1.0", "name",
"elasticsearch.version", Version.CURRENT.toString(), name,
"java.version", "1.8", "version",
"classname", classname, "1.0",
"has.native.controller", Boolean.toString(hasNativeController)); "elasticsearch.version",
Version.CURRENT.toString(),
"java.version",
"1.8",
"classname",
classname,
"has.native.controller",
Boolean.toString(hasNativeController)
);
} }
public void testPluginsDirMissing() throws Exception { public void testPluginsDirMissing() throws Exception {
@ -152,8 +155,10 @@ public class ListPluginsCommandTests extends ESTestCase {
"Java Version: 1.8", "Java Version: 1.8",
"Native Controller: false", "Native Controller: false",
"Extended Plugins: []", "Extended Plugins: []",
" * Classname: org.fake"), " * Classname: org.fake"
terminal.getOutput()); ),
terminal.getOutput()
);
} }
public void testPluginWithNativeController() throws Exception { public void testPluginWithNativeController() throws Exception {
@ -172,8 +177,10 @@ public class ListPluginsCommandTests extends ESTestCase {
"Java Version: 1.8", "Java Version: 1.8",
"Native Controller: true", "Native Controller: true",
"Extended Plugins: []", "Extended Plugins: []",
" * Classname: org.fake"), " * Classname: org.fake"
terminal.getOutput()); ),
terminal.getOutput()
);
} }
public void testPluginWithVerboseMultiplePlugins() throws Exception { public void testPluginWithVerboseMultiplePlugins() throws Exception {
@ -203,8 +210,10 @@ public class ListPluginsCommandTests extends ESTestCase {
"Java Version: 1.8", "Java Version: 1.8",
"Native Controller: false", "Native Controller: false",
"Extended Plugins: []", "Extended Plugins: []",
" * Classname: org.fake2"), " * Classname: org.fake2"
terminal.getOutput()); ),
terminal.getOutput()
);
} }
public void testPluginWithoutVerboseMultiplePlugins() throws Exception { public void testPluginWithoutVerboseMultiplePlugins() throws Exception {
@ -215,45 +224,45 @@ public class ListPluginsCommandTests extends ESTestCase {
assertEquals(buildMultiline("fake_plugin1", "fake_plugin2"), output); assertEquals(buildMultiline("fake_plugin1", "fake_plugin2"), output);
} }
public void testPluginWithoutDescriptorFile() throws Exception{ public void testPluginWithoutDescriptorFile() throws Exception {
final Path pluginDir = env.pluginsFile().resolve("fake1"); final Path pluginDir = env.pluginsFile().resolve("fake1");
Files.createDirectories(pluginDir); Files.createDirectories(pluginDir);
NoSuchFileException e = expectThrows(NoSuchFileException.class, () -> listPlugins(home)); NoSuchFileException e = expectThrows(NoSuchFileException.class, () -> listPlugins(home));
assertEquals(pluginDir.resolve(PluginInfo.ES_PLUGIN_PROPERTIES).toString(), e.getFile()); assertEquals(pluginDir.resolve(PluginInfo.ES_PLUGIN_PROPERTIES).toString(), e.getFile());
} }
public void testPluginWithWrongDescriptorFile() throws Exception{ public void testPluginWithWrongDescriptorFile() throws Exception {
final Path pluginDir = env.pluginsFile().resolve("fake1"); final Path pluginDir = env.pluginsFile().resolve("fake1");
PluginTestUtil.writePluginProperties(pluginDir, "description", "fake desc"); PluginTestUtil.writePluginProperties(pluginDir, "description", "fake desc");
IllegalArgumentException e = expectThrows( IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> listPlugins(home));
IllegalArgumentException.class,
() -> listPlugins(home));
final Path descriptorPath = pluginDir.resolve(PluginInfo.ES_PLUGIN_PROPERTIES); final Path descriptorPath = pluginDir.resolve(PluginInfo.ES_PLUGIN_PROPERTIES);
assertEquals( assertEquals("property [name] is missing in [" + descriptorPath.toString() + "]", e.getMessage());
"property [name] is missing in [" + descriptorPath.toString() + "]",
e.getMessage());
} }
public void testExistingIncompatiblePlugin() throws Exception { public void testExistingIncompatiblePlugin() throws Exception {
PluginTestUtil.writePluginProperties(env.pluginsFile().resolve("fake_plugin1"), PluginTestUtil.writePluginProperties(
"description", "fake desc 1", env.pluginsFile().resolve("fake_plugin1"),
"name", "fake_plugin1", "description",
"version", "1.0", "fake desc 1",
"elasticsearch.version", Version.fromString("1.0.0").toString(), "name",
"java.version", System.getProperty("java.specification.version"), "fake_plugin1",
"classname", "org.fake1"); "version",
"1.0",
"elasticsearch.version",
Version.fromString("1.0.0").toString(),
"java.version",
System.getProperty("java.specification.version"),
"classname",
"org.fake1"
);
buildFakePlugin(env, "fake desc 2", "fake_plugin2", "org.fake2"); buildFakePlugin(env, "fake desc 2", "fake_plugin2", "org.fake2");
MockTerminal terminal = listPlugins(home); MockTerminal terminal = listPlugins(home);
String message = "plugin [fake_plugin1] was built for Elasticsearch version 1.0 but version " + Version.CURRENT + " is required"; String message = "plugin [fake_plugin1] was built for Elasticsearch version 1.0 but version " + Version.CURRENT + " is required";
assertEquals( assertEquals("fake_plugin1\nfake_plugin2\n", terminal.getOutput());
"fake_plugin1\nfake_plugin2\n", assertEquals("WARNING: " + message + "\n", terminal.getErrorOutput());
terminal.getOutput());
assertEquals(
"WARNING: " + message + "\n",
terminal.getErrorOutput());
String[] params = {"-s"}; String[] params = { "-s" };
terminal = listPlugins(home, params); terminal = listPlugins(home, params);
assertEquals("fake_plugin1\nfake_plugin2\n", terminal.getOutput()); assertEquals("fake_plugin1\nfake_plugin2\n", terminal.getOutput());
} }

View File

@ -73,9 +73,7 @@ public class RemovePluginCommandTests extends ESTestCase {
Files.createDirectories(home.resolve("bin")); Files.createDirectories(home.resolve("bin"));
Files.createFile(home.resolve("bin").resolve("elasticsearch")); Files.createFile(home.resolve("bin").resolve("elasticsearch"));
Files.createDirectories(home.resolve("plugins")); Files.createDirectories(home.resolve("plugins"));
Settings settings = Settings.builder() Settings settings = Settings.builder().put("path.home", home).build();
.put("path.home", home)
.build();
env = TestEnvironment.newEnvironment(settings); env = TestEnvironment.newEnvironment(settings);
} }
@ -94,12 +92,19 @@ public class RemovePluginCommandTests extends ESTestCase {
void createPlugin(Path path, String name, Version version) throws IOException { void createPlugin(Path path, String name, Version version) throws IOException {
PluginTestUtil.writePluginProperties( PluginTestUtil.writePluginProperties(
path.resolve(name), path.resolve(name),
"description", "dummy", "description",
"name", name, "dummy",
"version", "1.0", "name",
"elasticsearch.version", version.toString(), name,
"java.version", System.getProperty("java.specification.version"), "version",
"classname", "SomeClass"); "1.0",
"elasticsearch.version",
version.toString(),
"java.version",
System.getProperty("java.specification.version"),
"classname",
"SomeClass"
);
} }
static MockTerminal removePlugin(String name, Path home, boolean purge) throws Exception { static MockTerminal removePlugin(String name, Path home, boolean purge) throws Exception {
@ -142,7 +147,9 @@ public class RemovePluginCommandTests extends ESTestCase {
VersionUtils.randomVersionBetween( VersionUtils.randomVersionBetween(
random(), random(),
Version.CURRENT.minimumIndexCompatibilityVersion(), Version.CURRENT.minimumIndexCompatibilityVersion(),
VersionUtils.getPreviousVersion())); VersionUtils.getPreviousVersion()
)
);
removePlugin("fake", home, randomBoolean()); removePlugin("fake", home, randomBoolean());
assertThat(Files.exists(env.pluginsFile().resolve("fake")), equalTo(false)); assertThat(Files.exists(env.pluginsFile().resolve("fake")), equalTo(false));
assertRemoveCleaned(env); assertRemoveCleaned(env);
@ -237,12 +244,15 @@ public class RemovePluginCommandTests extends ESTestCase {
return false; return false;
} }
}.main(new String[] { "-Epath.home=" + home, "fake" }, terminal); }.main(new String[] { "-Epath.home=" + home, "fake" }, terminal);
try (BufferedReader reader = new BufferedReader(new StringReader(terminal.getOutput())); try (
BufferedReader reader = new BufferedReader(new StringReader(terminal.getOutput()));
BufferedReader errorReader = new BufferedReader(new StringReader(terminal.getErrorOutput())) BufferedReader errorReader = new BufferedReader(new StringReader(terminal.getErrorOutput()))
) { ) {
assertEquals("-> removing [fake]...", reader.readLine()); assertEquals("-> removing [fake]...", reader.readLine());
assertEquals("ERROR: plugin [fake] not found; run 'elasticsearch-plugin list' to get list of installed plugins", assertEquals(
errorReader.readLine()); "ERROR: plugin [fake] not found; run 'elasticsearch-plugin list' to get list of installed plugins",
errorReader.readLine()
);
assertNull(reader.readLine()); assertNull(reader.readLine());
assertNull(errorReader.readLine()); assertNull(errorReader.readLine());
} }
@ -266,4 +276,3 @@ public class RemovePluginCommandTests extends ESTestCase {
} }
} }