Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Respect environment variables in jvm.options #16834

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
Expand Down Expand Up @@ -283,7 +282,7 @@ public List<String> getJvmOptions() {
}

private static final Pattern OPTION_DEFINITION = Pattern.compile("((?<start>\\d+)(?<range>-)?(?<end>\\d+)?:)?(?<option>-.*)$");

private static final Pattern ENV_VAR_PATTERN = Pattern.compile("\\$\\{([A-Z_][A-Z0-9_]*)\\}");
/**
*
* If the version syntax specified on a line matches the specified JVM options, the JVM option callback will be invoked with the JVM
Expand Down Expand Up @@ -372,13 +371,16 @@ private static Optional<String> jvmOptionFromLine(final int javaMajorVersion, fi
// Skip comments and blank lines
return Optional.empty();
}
final Matcher matcher = OPTION_DEFINITION.matcher(line);

String subbedLine = replaceEnvVariables(line, System.getenv());

final Matcher matcher = OPTION_DEFINITION.matcher(subbedLine);
if (matcher.matches()) {
final String start = matcher.group("start");
final String end = matcher.group("end");
if (start == null) {
// no range present, unconditionally apply the JVM option
return Optional.of(line);
return Optional.of(subbedLine);
} else {
final int lower = Integer.parseInt(start);
final int upper;
Expand All @@ -404,6 +406,20 @@ private static Optional<String> jvmOptionFromLine(final int javaMajorVersion, fi
return Optional.empty();
}

static String replaceEnvVariables(String line, Map<String,String> env) {
Matcher matcher = ENV_VAR_PATTERN.matcher(line);
StringBuilder sb = new StringBuilder();

while (matcher.find()) {
String varName = matcher.group(1);
String replacement = env.getOrDefault(varName, "");
matcher.appendReplacement(sb, replacement);
}
matcher.appendTail(sb);

return sb.toString();
}

private static final Pattern JAVA_VERSION = Pattern.compile("^(?:1\\.)?(?<javaMajorVersion>\\d+)(?:\\.\\d+)?$");

private static int javaMajorVersion() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,50 @@ private BufferedReader asReader(String s) {
return new BufferedReader(new StringReader(s));
}


@Test
public void testSingleEnvSubstitution() throws IOException {
String result = JvmOptionsParser.replaceEnvVariables("-XX:HeapDumpPath=${LOGSTASH_HOME}/heapdump.hprof",
Map.of("LOGSTASH_HOME", "/path/to/ls_home"));
assertEquals("-XX:HeapDumpPath=/path/to/ls_home/heapdump.hprof", result);
}

@Test
public void testMultipleEnvSubstitution() throws IOException {
String result = JvmOptionsParser.replaceEnvVariables("-XX:HeapDumpPath=${LOGSTASH_HOME}/${ABC}/heapdump.hprof",
Map.of("LOGSTASH_HOME", "/path/to/ls_home", "ABC", "abc"));
assertEquals("-XX:HeapDumpPath=/path/to/ls_home/abc/heapdump.hprof", result);
}

@Test
public void testEmptyEnvSubstitution() throws IOException {
String result = JvmOptionsParser.replaceEnvVariables("-XX:HeapDumpPath=${NOT_VALID}/heapdump.hprof", Map.of());
assertEquals("-XX:HeapDumpPath=/heapdump.hprof", result);
}

@Test
public void testNoSubstitution() throws IOException {
String result = JvmOptionsParser.replaceEnvVariables(" ", Map.of());
assertEquals(" ", result);
}

@Test
public void testEnvSubstitutionInFile() throws IOException {
File optionsFile = writeIntoTempOptionsFile(
writer -> writer.println("-Xlog:gc*,gc+age=trace,safepoint:file=${UNKNOWN}:"));

JvmOptionsParser.handleJvmOptions(new String[] {"/path/to/ls_home", optionsFile.toString()}, "-Dcli.opts=something");

final String output = outputStreamCaptor.toString();
assertTrue("env variable should be substituted ", output.contains("-Xlog:gc*,gc+age=trace,safepoint:file=:"));
}

@Test
public void testCommentedEnvSubstitution() throws IOException {
final BufferedReader options = asReader("# -Xlog:gc*,gc+age=trace,safepoint:file=${UNKNOWN}:");
final JvmOptionsParser.ParseResult res = JvmOptionsParser.parse(11, options);

assertTrue("no invalid lines can be present", res.getInvalidLines().isEmpty());
assertFalse(String.join(System.lineSeparator(), res.getJvmOptions()).contains("-Xlog:gc*,gc+age=trace,safepoint"));
}
}
Loading