mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-16 18:04:52 +00:00
Bootstrap should implement a denylist of Java versions (ranges) (#3164)
* Bootstrap should implement a denylist of Java versions (ranges) Signed-off-by: Andriy Redko <andriy.redko@aiven.io> * Addressing code review comments Signed-off-by: Andriy Redko <andriy.redko@aiven.io>
This commit is contained in:
parent
ad7ce4cd44
commit
677915dc00
@ -36,6 +36,7 @@ import org.apache.logging.log4j.LogManager;
|
|||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.apache.logging.log4j.message.ParameterizedMessage;
|
import org.apache.logging.log4j.message.ParameterizedMessage;
|
||||||
import org.apache.lucene.util.Constants;
|
import org.apache.lucene.util.Constants;
|
||||||
|
import org.opensearch.bootstrap.jvm.DenyJvmVersionsParser;
|
||||||
import org.opensearch.cluster.coordination.ClusterBootstrapService;
|
import org.opensearch.cluster.coordination.ClusterBootstrapService;
|
||||||
import org.opensearch.common.SuppressForbidden;
|
import org.opensearch.common.SuppressForbidden;
|
||||||
import org.opensearch.common.io.PathUtils;
|
import org.opensearch.common.io.PathUtils;
|
||||||
@ -224,11 +225,32 @@ final class BootstrapChecks {
|
|||||||
checks.add(new OnErrorCheck());
|
checks.add(new OnErrorCheck());
|
||||||
checks.add(new OnOutOfMemoryErrorCheck());
|
checks.add(new OnOutOfMemoryErrorCheck());
|
||||||
checks.add(new EarlyAccessCheck());
|
checks.add(new EarlyAccessCheck());
|
||||||
|
checks.add(new JavaVersionCheck());
|
||||||
checks.add(new AllPermissionCheck());
|
checks.add(new AllPermissionCheck());
|
||||||
checks.add(new DiscoveryConfiguredCheck());
|
checks.add(new DiscoveryConfiguredCheck());
|
||||||
return Collections.unmodifiableList(checks);
|
return Collections.unmodifiableList(checks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class JavaVersionCheck implements BootstrapCheck {
|
||||||
|
@Override
|
||||||
|
public BootstrapCheckResult check(BootstrapContext context) {
|
||||||
|
return DenyJvmVersionsParser.getDeniedJvmVersions()
|
||||||
|
.stream()
|
||||||
|
.filter(p -> p.test(getVersion()))
|
||||||
|
.findAny()
|
||||||
|
.map(
|
||||||
|
p -> BootstrapCheckResult.failure(
|
||||||
|
String.format(Locale.ROOT, "The current JVM version %s is not recommended for use: %s", getVersion(), p.getReason())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.orElseGet(() -> BootstrapCheckResult.success());
|
||||||
|
}
|
||||||
|
|
||||||
|
Runtime.Version getVersion() {
|
||||||
|
return Runtime.version();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static class HeapSizeCheck implements BootstrapCheck {
|
static class HeapSizeCheck implements BootstrapCheck {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* The OpenSearch Contributors require contributions made to
|
||||||
|
* this file be licensed under the Apache-2.0 license or a
|
||||||
|
* compatible open source license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.opensearch.bootstrap.jvm;
|
||||||
|
|
||||||
|
import org.opensearch.common.Nullable;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.UncheckedIOException;
|
||||||
|
import java.lang.Runtime.Version;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the list of JVM versions which should be denied to run Opensearch engine with due to discovered
|
||||||
|
* issues or flaws.
|
||||||
|
*/
|
||||||
|
public class DenyJvmVersionsParser {
|
||||||
|
public interface VersionPredicate extends Predicate<Version> {
|
||||||
|
String getReason();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SingleVersion implements VersionPredicate {
|
||||||
|
final private Version version;
|
||||||
|
final private String reason;
|
||||||
|
|
||||||
|
public SingleVersion(Version version, String reason) {
|
||||||
|
this.version = version;
|
||||||
|
this.reason = reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(Version v) {
|
||||||
|
return version.compareTo(v) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getReason() {
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class VersionRange implements VersionPredicate {
|
||||||
|
private Version lower;
|
||||||
|
private boolean lowerIncluded;
|
||||||
|
private Version upper;
|
||||||
|
private boolean upperIncluded;
|
||||||
|
private String reason;
|
||||||
|
|
||||||
|
public VersionRange(@Nullable Version lower, boolean lowerIncluded, @Nullable Version upper, boolean upperIncluded, String reason) {
|
||||||
|
this.lower = lower;
|
||||||
|
this.lowerIncluded = lowerIncluded;
|
||||||
|
this.upper = upper;
|
||||||
|
this.upperIncluded = upperIncluded;
|
||||||
|
this.reason = reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(Version v) {
|
||||||
|
if (lower != null) {
|
||||||
|
int compare = lower.compareTo(v);
|
||||||
|
if (compare > 0 || (compare == 0 && lowerIncluded != true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upper != null) {
|
||||||
|
int compare = upper.compareTo(v);
|
||||||
|
if (compare < 0 || (compare == 0 && upperIncluded != true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getReason() {
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Collection<VersionPredicate> getDeniedJvmVersions() {
|
||||||
|
try (
|
||||||
|
final InputStreamReader in = new InputStreamReader(
|
||||||
|
DenyJvmVersionsParser.class.getResourceAsStream("deny-jvm-versions.txt"),
|
||||||
|
StandardCharsets.UTF_8
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
try (final BufferedReader reader = new BufferedReader(in)) {
|
||||||
|
return reader.lines()
|
||||||
|
.map(String::trim)
|
||||||
|
// filter empty lines
|
||||||
|
.filter(line -> line.isEmpty() == false)
|
||||||
|
// filter out all comments
|
||||||
|
.filter(line -> line.startsWith("//") == false)
|
||||||
|
.map(DenyJvmVersionsParser::parse)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
} catch (final IOException ex) {
|
||||||
|
throw new UncheckedIOException("Unable to read the list of denied JVM versions", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse individual line from the list of denied JVM versions. Some version and version range examples are:
|
||||||
|
* <ul>
|
||||||
|
* <li>11.0.2: "... reason ..." - version 11.0.2</li>
|
||||||
|
* <li>[11.0.2, 11.0.14): "... reason ..." - versions 11.0.2.2 (included) to 11.0.14 (not included)</li>
|
||||||
|
* <li>[11.0.2, 11.0.14]: "... reason ..." - versions 11.0.2 to 11.0.14 (both included)</li>
|
||||||
|
* <li>[11.0.2,): "... reason ..." - versions 11.0.2 and higher</li>
|
||||||
|
* </ul>
|
||||||
|
* @param line line to parse
|
||||||
|
* @return version or version range predicate
|
||||||
|
*/
|
||||||
|
static VersionPredicate parse(String line) {
|
||||||
|
final String[] parts = Arrays.stream(line.split("[:]", 2)).map(String::trim).toArray(String[]::new);
|
||||||
|
|
||||||
|
if (parts.length != 2) {
|
||||||
|
throw new IllegalArgumentException("Unable to parse JVM version or version range: " + line);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String versionOrRange = parts[0];
|
||||||
|
final String reason = parts[1];
|
||||||
|
|
||||||
|
// dealing with version range here
|
||||||
|
if (versionOrRange.startsWith("[") == true || versionOrRange.startsWith("(") == true) {
|
||||||
|
if (versionOrRange.endsWith("]") == false && versionOrRange.endsWith(")") == false) {
|
||||||
|
throw new IllegalArgumentException("Unable to parse JVM version range: " + versionOrRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean lowerIncluded = versionOrRange.startsWith("[");
|
||||||
|
final boolean upperIncluded = versionOrRange.endsWith("]");
|
||||||
|
|
||||||
|
final String[] range = Arrays.stream(versionOrRange.substring(1, versionOrRange.length() - 1).split("[,]", 2))
|
||||||
|
.map(String::trim)
|
||||||
|
.toArray(String[]::new);
|
||||||
|
|
||||||
|
if (range.length != 2) {
|
||||||
|
throw new IllegalArgumentException("Unable to parse JVM version range: " + versionOrRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
Version lower = null;
|
||||||
|
if (range[0].isEmpty() == false && range[0].equals("*") == false) {
|
||||||
|
lower = Version.parse(range[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Version upper = null;
|
||||||
|
if (range[1].isEmpty() == false && range[1].equals("*") == false) {
|
||||||
|
upper = Version.parse(range[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new VersionRange(lower, lowerIncluded, upper, upperIncluded, reason);
|
||||||
|
} else {
|
||||||
|
// this is just a single version
|
||||||
|
return new SingleVersion(Version.parse(versionOrRange), reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
// Some version and version range examples are:
|
||||||
|
// 11.0.2: <... reason ...> version 11.0.2.
|
||||||
|
// [11.0.2, 11.0.14): <... reason ...> versions 11.0.2.2 (included) to 11.0.14 (not included)
|
||||||
|
// [11.0.2, 11.0.14]: <... reason ...> versions 11.0.2 to 11.0.14 (both included)
|
||||||
|
// [11.0.2,): <... reason ...> versions 11.0.2 and higher
|
||||||
|
// [11.0.2,*): <... reason ...> versions 11.0.2 and higher
|
||||||
|
// (, 11.0.14]: <... reason ...> versions up to 11.0.14 (included)
|
||||||
|
// (*, 11.0.14]: <... reason ...> versions up to 11.0.14 (included)
|
||||||
|
|
||||||
|
[11.0.2, 11.0.14): for more details, please check https://github.com/opensearch-project/OpenSearch/issues/2791 and https://bugs.openjdk.java.net/browse/JDK-8259541
|
@ -47,6 +47,7 @@ import org.opensearch.node.NodeValidationException;
|
|||||||
import org.opensearch.test.AbstractBootstrapCheckTestCase;
|
import org.opensearch.test.AbstractBootstrapCheckTestCase;
|
||||||
import org.hamcrest.Matcher;
|
import org.hamcrest.Matcher;
|
||||||
|
|
||||||
|
import java.lang.Runtime.Version;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -745,4 +746,32 @@ public class BootstrapChecksTests extends AbstractBootstrapCheckTestCase {
|
|||||||
// Validate the deprecated setting is still valid during the node bootstrap.
|
// Validate the deprecated setting is still valid during the node bootstrap.
|
||||||
ensureChecksPass.accept(Settings.builder().putList(ClusterBootstrapService.INITIAL_MASTER_NODES_SETTING.getKey()));
|
ensureChecksPass.accept(Settings.builder().putList(ClusterBootstrapService.INITIAL_MASTER_NODES_SETTING.getKey()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testJvmVersionCheck() throws NodeValidationException {
|
||||||
|
final AtomicReference<Version> version = new AtomicReference<>(Version.parse("11.0.13+8"));
|
||||||
|
final BootstrapCheck check = new BootstrapChecks.JavaVersionCheck() {
|
||||||
|
@Override
|
||||||
|
Version getVersion() {
|
||||||
|
return version.get();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
final NodeValidationException e = expectThrows(
|
||||||
|
NodeValidationException.class,
|
||||||
|
() -> BootstrapChecks.check(emptyContext, true, Collections.singletonList(check))
|
||||||
|
);
|
||||||
|
assertThat(
|
||||||
|
e.getMessage(),
|
||||||
|
containsString(
|
||||||
|
"The current JVM version 11.0.13+8 is not recommended for use: "
|
||||||
|
+ "for more details, please check https://github.com/opensearch-project/OpenSearch/issues/2791 and https://bugs.openjdk.java.net/browse/JDK-8259541"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
version.set(Version.parse("11.0.14"));
|
||||||
|
BootstrapChecks.check(emptyContext, true, Collections.singletonList(check));
|
||||||
|
|
||||||
|
version.set(Runtime.version());
|
||||||
|
BootstrapChecks.check(emptyContext, true, Collections.singletonList(check));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* The OpenSearch Contributors require contributions made to
|
||||||
|
* this file be licensed under the Apache-2.0 license or a
|
||||||
|
* compatible open source license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.opensearch.bootstrap.jvm;
|
||||||
|
|
||||||
|
import org.opensearch.bootstrap.jvm.DenyJvmVersionsParser.VersionPredicate;
|
||||||
|
import org.opensearch.test.OpenSearchTestCase;
|
||||||
|
|
||||||
|
import java.lang.Runtime.Version;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.CoreMatchers.not;
|
||||||
|
import static org.hamcrest.collection.IsEmptyCollection.empty;
|
||||||
|
|
||||||
|
public class DenyJvmVersionsParserTests extends OpenSearchTestCase {
|
||||||
|
public void testDefaults() {
|
||||||
|
final Collection<VersionPredicate> versions = DenyJvmVersionsParser.getDeniedJvmVersions();
|
||||||
|
assertThat(versions, not(empty()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSingleVersion() {
|
||||||
|
final VersionPredicate predicate = DenyJvmVersionsParser.parse("11.0.2: know to be flawed version");
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.2")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.1")), is(false));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.3")), is(false));
|
||||||
|
assertThat(predicate.getReason(), equalTo("know to be flawed version"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testVersionRangeLowerIncluded() {
|
||||||
|
final VersionPredicate predicate = DenyJvmVersionsParser.parse("[11.0.2, 11.0.14): know to be flawed version");
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.2")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.1")), is(false));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.13+1")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.14")), is(false));
|
||||||
|
assertThat(predicate.getReason(), equalTo("know to be flawed version"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testVersionRangeUpperIncluded() {
|
||||||
|
final VersionPredicate predicate = DenyJvmVersionsParser.parse("[11.0.2,): know to be flawed version");
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.2")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.1")), is(false));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.13+1")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.14")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("17.2.1")), is(true));
|
||||||
|
assertThat(predicate.getReason(), equalTo("know to be flawed version"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testVersionRangeLowerAndUpperIncluded() {
|
||||||
|
final VersionPredicate predicate = DenyJvmVersionsParser.parse("[11.0.2, 11.0.14]: know to be flawed version");
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.2")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.1")), is(false));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.13+1")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.14")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.14.1")), is(false));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.15")), is(false));
|
||||||
|
assertThat(predicate.getReason(), equalTo("know to be flawed version"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllVersionsRange() {
|
||||||
|
final VersionPredicate predicate = DenyJvmVersionsParser.parse("(,): know to be flawed version");
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.2")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.1")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.13+1")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.14")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.14.1")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.15")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("17.2.1")), is(true));
|
||||||
|
assertThat(predicate.getReason(), equalTo("know to be flawed version"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAllVersionsRangeIncluded() {
|
||||||
|
final VersionPredicate predicate = DenyJvmVersionsParser.parse("[*, *]: know to be flawed version");
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.2")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.1")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.13+1")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.14")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.14.1")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("11.0.15")), is(true));
|
||||||
|
assertThat(predicate.test(Version.parse("17.2.1")), is(true));
|
||||||
|
assertThat(predicate.getReason(), equalTo("know to be flawed version"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testIncorrectVersionRanges() {
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> DenyJvmVersionsParser.parse("[*, *: know to be flawed version"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> DenyJvmVersionsParser.parse("*, *: know to be flawed version"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> DenyJvmVersionsParser.parse("*, *): know to be flawed version"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> DenyJvmVersionsParser.parse("(): know to be flawed version"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> DenyJvmVersionsParser.parse("[]: know to be flawed version"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> DenyJvmVersionsParser.parse("[,]"));
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> DenyJvmVersionsParser.parse("11.0.2"));
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user