Accept settings in snake case in Docker image (#74327)

Closes #74036. Since some orchestration platforms forbid periods in
environment variable names, allow Docker users to pass settings to ES
using an alternative name scheme. For example:

    bootstrap.memory_lock

...becomes:

    ES_BOOTSTRAP_MEMORY__LOCK

The setting name is uppercased, prefixed, all underscores are converted
to double underscores, and all periods are converted to underscores.
This commit is contained in:
Rory Hunter 2021-07-09 19:46:58 +01:00 committed by GitHub
parent e4df4d7205
commit d08b851a5b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 85 additions and 5 deletions

View file

@ -111,7 +111,7 @@ if [[ "$ES_DISTRIBUTION_TYPE" == "docker" ]]; then
# Parse Docker env vars to customize Elasticsearch
#
# e.g. Setting the env var cluster.name=testcluster
# e.g. Setting the env var cluster.name=testcluster or ES_CLUSTER_NAME=testcluster
#
# will cause Elasticsearch to be invoked with -Ecluster.name=testcluster
#
@ -122,11 +122,35 @@ if [[ "$ES_DISTRIBUTION_TYPE" == "docker" ]]; then
while IFS='=' read -r envvar_key envvar_value
do
# Elasticsearch settings need to have at least two dot separated lowercase
# words, e.g. `cluster.name`
if [[ "$envvar_key" =~ ^[a-z0-9_]+\.[a-z0-9_]+ ]]; then
if [[ ! -z $envvar_value ]]; then
# words, e.g. `cluster.name`, or uppercased with underscore separators and
# prefixed with `ES_`, e.g. `ES_CLUSTER_NAME`. Underscores in setting names
# are escaped by writing them as a double-underscore e.g. "__"
if [[ ! -z "$envvar_value" ]]; then
if [[ "$envvar_key" =~ ^[a-z0-9_]+\.[a-z0-9_]+ ]]; then
es_opt="-E${envvar_key}=${envvar_value}"
es_arg_array+=("${es_opt}")
elif [[ "$envvar_key" =~ ^ES(_{1,2}[A-Z]+)+$ ]]; then
case "$envvar_key" in
# Do nothing for these. Not all of these are actually exported into the environment by our scripts,
# and so don't appear in the output of the `env` command, but it's better to be safe than sorry
# in case a user exported them in their own shell for some reason.
ES_DISTRIBUTION_FLAVOR) ;;
ES_DISTRIBUTION_TYPE) ;;
ES_HOME) ;;
ES_JAVA_HOME) ;;
ES_JAVA_OPTS) ;;
ES_KEYSTORE_PASSPHRASE_FILE) ;;
ES_LOG_STYLE) ;;
ES_PATH_CONF) ;;
ES_SD_NOTIFY) ;;
ES_TMPDIR) ;;
*)
# The long-hand sed `y` command works in any sed variant.
envvar_key="$(echo "$envvar_key" | sed -e 's/^ES_//; s/_/./g ; s/\.\./_/g; y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' )"
es_opt="-E${envvar_key}=${envvar_value}"
es_arg_array+=("${es_opt}")
;;
esac
fi
fi
done <<< "$(env)"

View file

@ -339,7 +339,19 @@ over the configuration files in the image.
You can set individual {es} configuration parameters using Docker environment variables.
The <<docker-compose-file, sample compose file>> and the
<<docker-cli-run-dev-mode, single-node example>> use this method.
<<docker-cli-run-dev-mode, single-node example>> use this method. You can
use the setting name directly as the environment variable name. If
you cannot do this, for example because your orchestration platform forbids
periods in environment variable names, then you can use an alternative
style by converting the setting name as follows.
. Change the setting name to uppercase
. Prefix it with `ES_`
. Escape any underscores (`_`) by duplicating them
. Convert all periods (`.`) to underscores (`_`)
For example, `-e bootstrap.memory_lock=true` becomes
`-e ES_BOOTSTRAP_MEMORY__LOCK=true`.
To use the contents of a file to set an environment variable, suffix the environment
variable name with `_FILE`. This is useful for passing secrets such as passwords to {es}

View file

@ -486,6 +486,50 @@ public class DockerTests extends PackagingTestCase {
assertThat(result.stdout, containsString("java.net.UnknownHostException: this.is.not.valid"));
}
/**
* Check that settings are applied when they are supplied as environment variables with names that are:
* <ul>
* <li>Prefixed with {@code ES_}</li>
* <li>All uppercase</li>
* <li>Dots (periods) are converted to underscores</li>
* <li>Underscores in setting names are escaped by doubling them</li>
* </ul>
*/
public void test086EnvironmentVariablesInSnakeCaseAreTranslated() {
// Note the double-underscore in the var name here, which retains the underscore in translation
installation = runContainer(distribution(), builder().envVars(Map.of("ES_XPACK_SECURITY_FIPS__MODE_ENABLED", "false")));
final Optional<String> commandLine = sh.run("bash -c 'COLUMNS=2000 ps ax'").stdout.lines()
.filter(line -> line.contains("org.elasticsearch.bootstrap.Elasticsearch"))
.findFirst();
assertThat(commandLine.isPresent(), equalTo(true));
assertThat(commandLine.get(), containsString("-Expack.security.fips_mode.enabled=false"));
}
/**
* Check that environment variables that do not match the criteria for translation to settings are ignored.
*/
public void test087EnvironmentVariablesInIncorrectFormatAreIgnored() {
final Map<String, String> envVars = new HashMap<>();
// No ES_ prefix
envVars.put("XPACK_SECURITY_FIPS__MODE_ENABLED", "false");
// Not underscore-separated
envVars.put("ES.XPACK.SECURITY.FIPS_MODE.ENABLED", "false");
// Not uppercase
envVars.put("es_xpack_security_fips__mode_enabled", "false");
installation = runContainer(distribution(), builder().envVars(envVars));
final Optional<String> commandLine = sh.run("bash -c 'COLUMNS=2000 ps ax'").stdout.lines()
.filter(line -> line.contains("org.elasticsearch.bootstrap.Elasticsearch"))
.findFirst();
assertThat(commandLine.isPresent(), equalTo(true));
assertThat(commandLine.get(), not(containsString("-Expack.security.fips_mode.enabled=false")));
}
/**
* Check whether the elasticsearch-certutil tool has been shipped correctly,
* and if present then it can execute.