mirror of
https://github.com/elastic/logstash.git
synced 2025-06-28 09:46:03 -04:00
Respect environment variables in jvm.options (#16834)
JvmOptionsParser adds support for ${VAR:default} syntax when parsing jvm.options - allow dynamic resolution of environment variables in the jvm.options file - enables fallback to default value when the environment variable is not set
This commit is contained in:
parent
de6a6c5b0f
commit
ef36df6b81
3 changed files with 97 additions and 5 deletions
|
@ -30,7 +30,7 @@
|
||||||
## basic
|
## basic
|
||||||
|
|
||||||
# set the I/O temp directory
|
# set the I/O temp directory
|
||||||
#-Djava.io.tmpdir=$HOME
|
#-Djava.io.tmpdir=${HOME}
|
||||||
|
|
||||||
# set to headless, just in case
|
# set to headless, just in case
|
||||||
-Djava.awt.headless=true
|
-Djava.awt.headless=true
|
||||||
|
|
|
@ -32,7 +32,6 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -283,7 +282,6 @@ public class JvmOptionsParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Pattern OPTION_DEFINITION = Pattern.compile("((?<start>\\d+)(?<range>-)?(?<end>\\d+)?:)?(?<option>-.*)$");
|
private static final Pattern OPTION_DEFINITION = Pattern.compile("((?<start>\\d+)(?<range>-)?(?<end>\\d+)?:)?(?<option>-.*)$");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* If the version syntax specified on a line matches the specified JVM options, the JVM option callback will be invoked with the JVM
|
* If the version syntax specified on a line matches the specified JVM options, the JVM option callback will be invoked with the JVM
|
||||||
|
@ -372,13 +370,16 @@ public class JvmOptionsParser {
|
||||||
// Skip comments and blank lines
|
// Skip comments and blank lines
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
final Matcher matcher = OPTION_DEFINITION.matcher(line);
|
|
||||||
|
String subbedLine = resolveEnvVar(line, System.getenv());
|
||||||
|
|
||||||
|
final Matcher matcher = OPTION_DEFINITION.matcher(subbedLine);
|
||||||
if (matcher.matches()) {
|
if (matcher.matches()) {
|
||||||
final String start = matcher.group("start");
|
final String start = matcher.group("start");
|
||||||
final String end = matcher.group("end");
|
final String end = matcher.group("end");
|
||||||
if (start == null) {
|
if (start == null) {
|
||||||
// no range present, unconditionally apply the JVM option
|
// no range present, unconditionally apply the JVM option
|
||||||
return Optional.of(line);
|
return Optional.of(subbedLine);
|
||||||
} else {
|
} else {
|
||||||
final int lower = Integer.parseInt(start);
|
final int lower = Integer.parseInt(start);
|
||||||
final int upper;
|
final int upper;
|
||||||
|
@ -404,6 +405,23 @@ public class JvmOptionsParser {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Pattern ENV_VAR_PATTERN = Pattern.compile("\\$\\{([a-zA-Z_.][a-zA-Z0-9_.]*)(?::([^}]*))?\\}");
|
||||||
|
|
||||||
|
static String resolveEnvVar(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 defaultValue = Optional.ofNullable(matcher.group(2)).orElse("");
|
||||||
|
String replacement = env.getOrDefault(varName, defaultValue);
|
||||||
|
matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
|
||||||
|
}
|
||||||
|
matcher.appendTail(sb);
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private static final Pattern JAVA_VERSION = Pattern.compile("^(?:1\\.)?(?<javaMajorVersion>\\d+)(?:\\.\\d+)?$");
|
private static final Pattern JAVA_VERSION = Pattern.compile("^(?:1\\.)?(?<javaMajorVersion>\\d+)(?:\\.\\d+)?$");
|
||||||
|
|
||||||
private static int javaMajorVersion() {
|
private static int javaMajorVersion() {
|
||||||
|
|
|
@ -198,4 +198,78 @@ public class JvmOptionsParserTest {
|
||||||
return new BufferedReader(new StringReader(s));
|
return new BufferedReader(new StringReader(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingleEnvSub() throws IOException {
|
||||||
|
String result = JvmOptionsParser.resolveEnvVar("-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 testMultipleEnvSub() throws IOException {
|
||||||
|
String result = JvmOptionsParser.resolveEnvVar("-XX:HeapDumpPath=${LOGSTASH_HOME}/${DATA}/heapdump.hprof",
|
||||||
|
Map.of("LOGSTASH_HOME", "/path/to/ls_home", "DATA", "data"));
|
||||||
|
assertEquals("-XX:HeapDumpPath=/path/to/ls_home/data/heapdump.hprof", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPeriodEnvSub() throws IOException {
|
||||||
|
String result = JvmOptionsParser.resolveEnvVar("-XX:HeapDumpPath=${.HOME}/heapdump.hprof",
|
||||||
|
Map.of(".HOME", "/path/to/.home"));
|
||||||
|
assertEquals("-XX:HeapDumpPath=/path/to/.home/heapdump.hprof", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEmptyEnvSub() throws IOException {
|
||||||
|
String result = JvmOptionsParser.resolveEnvVar("-XX:HeapDumpPath=${NOT_VALID}/heapdump.hprof", Map.of());
|
||||||
|
assertEquals("-XX:HeapDumpPath=/heapdump.hprof", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoSub() throws IOException {
|
||||||
|
String result = JvmOptionsParser.resolveEnvVar(" ", Map.of());
|
||||||
|
assertEquals(" ", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnvSubWithDefault() throws IOException {
|
||||||
|
String result = JvmOptionsParser.resolveEnvVar("-XX:HeapDumpPath=${LOGSTASH_HOME:/usr/share/logstash}/${DATA:data}/heapdump.hprof",
|
||||||
|
Map.of());
|
||||||
|
assertEquals("-XX:HeapDumpPath=/usr/share/logstash/data/heapdump.hprof", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnvSubWithDefaultSpecialChar() throws IOException {
|
||||||
|
String result = JvmOptionsParser.resolveEnvVar("-XX:HeapDumpPath=${LOGSTASH_HOME:/usr/share/logstash}/${DATA:{$crazy!enough?'bless'@[you]}/heapdump.hprof",
|
||||||
|
Map.of());
|
||||||
|
assertEquals("-XX:HeapDumpPath=/usr/share/logstash/{$crazy!enough?'bless'@[you]/heapdump.hprof", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnvSubWithDefaultOverwritten() throws IOException {
|
||||||
|
String result = JvmOptionsParser.resolveEnvVar("-XX:HeapDumpPath=${LOGSTASH_HOME:/usr/share/logstash}/${DATA:data}/heapdump.hprof",
|
||||||
|
Map.of("DATA", "data2"));
|
||||||
|
assertEquals("-XX:HeapDumpPath=/usr/share/logstash/data2/heapdump.hprof", result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnvSubInFile() 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 testCommentedEnvSub() 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…
Add table
Add a link
Reference in a new issue