From 2955740a6e1009a165b844cd4b06ab4561145f5f Mon Sep 17 00:00:00 2001 From: muxator Date: Thu, 21 Mar 2019 01:37:19 +0100 Subject: [PATCH] Settings.js: support syntax for default values +---------------------------+---------------+------------------+ | Configuration string in | Value of | Resulting confi- | | settings.json | ENV_VAR | guration value | |---------------------------|---------------|------------------| | "${ENV_VAR}" | "some_string" | "some_string" | | "${ENV_VAR}" | "9001" | 9001 | | "${ENV_VAR}" | undefined | null | | "${ENV_VAR:some_default}" | "some_string" | "some_string" | | "${ENV_VAR:some_default}" | undefined | "some_default" | +---------------------------+---------------+------------------+ Mention this briefly in the main README.md, also. Closes #3578. --- README.md | 1 + docker/README.md | 2 +- settings.json.template | 33 +++++++++++++++++++-------------- src/node/utils/Settings.js | 27 ++++++++++++++++++++------- 4 files changed, 41 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index c7ca0d4d6..3b8ff6184 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ If cloning to a subdirectory within another project, you may need to do the foll You can modify the settings in `settings.json`. If you need to handle multiple settings files, you can pass the path to a settings file to `bin/run.sh` using the `-s|--settings` option: this allows you to run multiple Etherpad instances from the same installation. Similarly, `--credentials` can be used to give a settings override file, `--apikey` to give a different APIKEY.txt file and `--sessionkey` to give a non-default SESSIONKEY.txt. +**Each configuration parameter can also be set via an environment variable**, using the syntax `"${ENV_VAR}"` or `"${ENV_VAR:default_value}"`. For details, refer to `settings.json.template`. Once you have access to your /admin section settings can be modified through the web browser. You should use a dedicated database such as "mysql", if you are planning on using etherpad-in a production environment, since the "dirtyDB" database driver is only for testing and/or development purposes. diff --git a/docker/README.md b/docker/README.md index 87d6e81ea..ece7b7951 100644 --- a/docker/README.md +++ b/docker/README.md @@ -14,7 +14,7 @@ cp ../settings.json.template settings.json [ further edit your settings.json as needed] ``` -**Each configuration parameter can also be set via an environment variable**, using the syntax `"${ENV_VAR_NAME}"`. For details, refer to `settings.json.template`. +**Each configuration parameter can also be set via an environment variable**, using the syntax `"${ENV_VAR}"` or `"${ENV_VAR:default_value}"`. For details, refer to `settings.json.template`. Build the version you prefer: ```bash diff --git a/settings.json.template b/settings.json.template index 74f5872dd..535e502bf 100644 --- a/settings.json.template +++ b/settings.json.template @@ -11,33 +11,38 @@ * ================================= * * All the configuration values can be read from environment variables using the - * syntax "${ENV_VAR}". + * syntax "${ENV_VAR}" or "${ENV_VAR:default_value}". + * * This is useful, for example, when running in a Docker container. * * EXAMPLE: - * "port": "${PORT}" + * "port": "${PORT:9001}" * "minify": "${MINIFY}" - * "skinName": "${SKIN_NAME}" + * "skinName": "${SKIN_NAME:colibris}" * * Would read the configuration values for those items from the environment * variables PORT, MINIFY and SKIN_NAME. + * If PORT and SKIN_NAME variables were not defined, the default values 9001 and + * "colibris" would be used. The configuration value "minify", on the other + * hand, does not have a default indicated. Thus, if the environment variable + * MINIFY were undefined, "minify" would be null (do not do this). * * REMARKS: * Please note that variable substitution always needs to be quoted. * - * "port": 9001, <-- Literal values. When not using - * "minify": false substitution, only strings must be quoted. - * "skinName": "colibris" Booleans and numbers must not. + * "port": 9001, <-- Literal values. When not using + * "minify": false substitution, only strings must be + * "skinName": "colibris" quoted. Booleans and numbers must not. * - * "port": "${PORT}" <-- CORRECT: if you want to use a variable - * "minify": "${MINIFY}" substitution, put quotes around its name, - * "skinName": "${SKIN_NAME}" even if the required value is a number or a - * boolean. - * Etherpad will take care of rewriting it to - * the proper type if necessary. + * "port": "${PORT:9001}" <-- CORRECT: if you want to use a variable + * "minify": "${MINIFY:true}" substitution, put quotes around its name, + * "skinName": "${SKIN_NAME}" even if the required value is a number or + * a boolean. + * Etherpad will take care of rewriting it + * to the proper type if necessary. * - * "port": ${PORT} <-- ERROR: this is not valid json. Quotes - * "minify": ${MINIFY} around variable names are missing. + * "port": ${PORT:9001} <-- ERROR: this is not valid json. Quotes + * "minify": ${MINIFY} around variable names are missing. * "skinName": ${SKIN_NAME} * */ diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index 4ba07f3fb..8de69fcf7 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -400,8 +400,8 @@ function coerceValue(stringValue) { /** * Takes a javascript object containing Etherpad's configuration, and returns * another object, in which all the string properties whose value is of the form - * "${ENV_VAR}" got their value replaced with the contents of the given - * environment variable. + * "${ENV_VAR}" or "${ENV_VAR:default_value}" got their value replaced with the + * contents of the given environment variable, or with a default value. * * By definition, an environment variable's value is always a string. However, * the code base makes use of the various json types. To maintain compatiblity, @@ -422,6 +422,8 @@ function coerceValue(stringValue) { * | "${ENV_VAR}" | "some_string" | "some_string" | * | "${ENV_VAR}" | "9001" | 9001 | * | "${ENV_VAR}" | undefined | null | + * | "${ENV_VAR:some_default}" | "some_string" | "some_string" | + * | "${ENV_VAR:some_default}" | undefined | "some_default" | * +---------------------------+---------------+------------------+ * * IMPLEMENTATION NOTE: variable substitution is performed doing a round trip @@ -455,9 +457,10 @@ function lookupEnvironmentVariables(obj) { /* * Let's check if the string value looks like a variable expansion (e.g.: - * "${ENV_VAR}") + * "${ENV_VAR}" or "${ENV_VAR:default_value}") */ - const match = value.match(/^\$\{(.*)\}$/); + // MUXATOR 2019-03-21: we could use named capture groups here once we migrate to nodejs v10 + const match = value.match(/^\$\{([^:]*)(:(.*))?\}$/); if (match === null) { // no match: use the value literally, without any substitution @@ -465,12 +468,16 @@ function lookupEnvironmentVariables(obj) { return value; } - // we found the name of an environment variable. Let's read its value. + /* + * We found the name of an environment variable. Let's read its actual value + * and its default value, if given + */ const envVarName = match[1]; const envVarValue = process.env[envVarName]; + const defaultValue = match[3]; - if (envVarValue === undefined) { - console.warn(`Environment variable "${envVarName}" does not contain any value for configuration key "${key}". Returning null. Please check your configuration and environment settings.`); + if ((envVarValue === undefined) && (defaultValue === undefined)) { + console.warn(`Environment variable "${envVarName}" does not contain any value for configuration key "${key}", and no default was given. Returning null. Please check your configuration and environment settings.`); /* * We have to return null, because if we just returned undefined, the @@ -479,6 +486,12 @@ function lookupEnvironmentVariables(obj) { return null; } + if ((envVarValue === undefined) && (defaultValue !== undefined)) { + console.debug(`Environment variable "${envVarName}" not found for configuration key "${key}". Falling back to default value.`); + + return coerceValue(defaultValue); + } + // envVarName contained some value. /*