-
Notifications
You must be signed in to change notification settings - Fork 10
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
Support backticked environment variables in levels of config #37
Comments
I'd suggest to pass that information through YAML tags rather than through backticks. MyServiceClass:
my_config_prop: !env 'MY_ENV_VAR' That would be backward compatible with the existing configs and we wouldn't have to apply some magic rules for all the string values in the configs. That also would be extensible and potentially in the future we might add support for more tags (e.g. something like |
Since environment variables can be modified at runtime, but config is cached at boot, you'll need to be extremely careful that you don't rely on env vars during boot that aren't set yet (or that are subsequently changed). I suggest if you implement such a config resolution strategy, that you make it run-time not cache-time. (i.e. make it a middleware that evaluates on Config::inst()->get() similar to how extensions work). The literal back-ticked value would be cached. |
@dnsl48 I am against using |
TL;DR: A much more concise version of this is here: silverstripe/silverstripe-framework#7987 (comment). For anyone interested in reading a novel, carry on below. 😅 I came here wanting something similar myself. But, in my case, I not only wanted to see my environment variables interpolated in my YAML config, I also wanted to consolidate the definition of lots of environment-specific configuration into YAML instead of having them all in PHP constants, since I'm still on SS v3 and I need to eventually migrate to SS v4. Also in the interim, I need to work in containers & Kubernetes environments that rely more on environment variables instead of constants, which are extremely difficult to manage when you have a large number of environments (we have like 5 environments where we've deployed code, which I've coined "deployment environments"). So basically I needed to solve these problems:
Unfortunately, SS v3 relies very heavily on If anyone's interested in that code, please let me know and I could work on a gist. But in the meantime, here's a VERY basic example of that YAML structure and the supporting PHP code responsible for initializing those environment variables which are germane to this particular issue, in case it helps! Example YAML and supporting PHP code (excludes ---
##
## Contains default site configuration for ALL environments and overridden on a per deployment-environment basis. All
## other environment configs will run after this one thanks to the '#mysite-defaults' entry in their respective headers.
##
## This leverages SilverStripe's built-in YAML configuration capability. For more details on how this works, please see:
## https://docs.silverstripe.org/en/4/developer_guides/configuration/configuration/
##
Name: mysite-defaults
After:
- 'framework/*'
- 'cms/*'
---
Globals:
##
## NON-SECRET environment variables which are automatically loaded and accessed as environment variables throughout
## the codebase via the Environment::getEnv() method. This is for any variables that aren't secret and therefore can
## still be committed to code. This is useful since we have so many environments.
##
## These are automatically initialized by Globals::init().
##
## IMPORTANT:
##
## 1. Please only override the necessary values in the environment-specific YAMLs.
##
## 2. Actual environment variables and values defined in ".env" will take precedence over any values defined in YAML.
##
## 3. Variables that MUST be defined as actual environment variables are only *documented* here and must be placed
## either in .env or defined as an environment variable (depending on hosting environment) so that they are never
## committed. For example, all documented but non-committed environment variables should just be COMMENTS following
## this format:
##
## Secrets:
## #ENV_VAR_NAME="SECRET"
##
## Secrets with non-secret defaults (i.e. only secret if overridden):
## ENV_VAR_NAME: 'value' # SECRET IF OVERRIDDEN
##
## Non-Secrets:
## #ENV_VAR_NAME=VARIES
##
## This allows them to be easily copied into .env and then modified.
##
## 4. All defaults defined here are DEVELOPMENT/TESTING DEFAULTS. Production values must be defined elsewhere!
##
Environment:
# The special environment variable corresponding with this specific deployment (e.g. 'prod', 'uat', 'qa', 'dev',
# 'vm' and etc). All possible values can be found in the BASE_DOMAINS constant. All domains/subdomains are then
# derived from this initial value, as well as all subsequent automated configurations.
#
# IMPORTANT: Every environment MUST define this environment variable. Also, the "deployment environment" setting
# here is not to be confused with the "SilverStripe environment" setting.
# TODO: Should most these notes move to the .env.example file?
#DEPLOYMENT_ENVIRONMENT=VARIES
# Location where SilverStripe caches (class manifests, templates, and other cached values) should be stored.
# If empty (default), the cache will be stored under the website root as 'silverstripe-cache'. Please be sure to
# override this in development to prevent caches from being stored in website directory shared with the host machine.
# IMPORTANT: If used, this value MUST be defined as an actual environment variable due to how early it is needed!
#TEMP_PATH=VARIES
# SilverStripe environment type: dev, test, live
SS_ENVIRONMENT_TYPE: 'dev'
#####################
## DATABASE CONFIG ##
#####################
# Non-secret database values
SS_DATABASE_SERVER: ''
SS_DATABASE_NAME: ''
#SS_DATABASE_USERNAME="SECRET"
#SS_DATABASE_PASSWORD="SECRET"
# Delegate readonly queries to another server, enable this and set the PORT. All other settings will be copied from
# the main database configuration, however: You can also define an alternative server, DB name, username and password.
# See all constants and where this is controlled: CustomMySQLDatabase
SS_READONLY_DATABASE_ENABLED: false
SS_READONLY_DATABASE_PORT: ''
#########################
## DEFAULT ADMIN LOGIN ##
#########################
# Default CMS admin username and password.
#SS_DEFAULT_ADMIN_USERNAME="SECRET"
#SS_DEFAULT_ADMIN_PASSWORD="SECRET"
##
## Generic and globally accessible values. These are *effectively* constants that can vary per-environment,
## committed code and can be overridden on a per deployment-environment basis. When accessed via Globals::constant()),
## these values can also contain secrets imported from environment variables as well (useful for consistency and
## reusability).
##
## NOTE: You can access these values via either:
##
## 1. Globals::constant('CONSTANT_NAME') - Strongly recommended for all site code, since it is not easily
## inspected using IDE intellisense. It also ensures developers know to look in this file for the definitions.
##
## 2. CONSTANT_NAME - As an actual constant. However, this is discouraged as it's only intended for SilverStripe's internals.
##
Constants:
# See above. Must be defined as constants, so interpolate environment values now.
SS_DEFAULT_ADMIN_USERNAME: '`SS_DEFAULT_ADMIN_USERNAME`'
SS_DEFAULT_ADMIN_PASSWORD: '`SS_DEFAULT_ADMIN_PASSWORD`'
Then somewhere in the <?php
use SilverStripe\Core\Environment;
/**
* Do things that would normally be done in SilverStripe v3's ConfigureFromEnv.php
*
* TODO: SSv4: This entire closure can be removed as it's handled automatically in v4.
*/
call_user_func(function() {
// Initialize SilverStripe's environment type.
Config::inst()->update('Director', 'environment_type', Environment::getEnv('SS_ENVIRONMENT_TYPE'));
// Initialize database confirmation.
global $databaseConfig;
$databaseConfig = array(
"type" => "MySQLDatabase", // NOTE: Will use Injector to pull our custom class instead.
"server" => Environment::getEnv('SS_DATABASE_SERVER'),
"username" => Environment::getEnv('SS_DATABASE_USERNAME'),
"password" => Environment::getEnv('SS_DATABASE_PASSWORD'),
"database" => Environment::getEnv('SS_DATABASE_NAME'),
);
DatabaseAdapterRegistry::autoconfigure();
// Allow a default user/pass in non-live environments. Also normally performed in v3's ConfigureFromEnv.php.
if(!Director::isLive() && defined('SS_DEFAULT_ADMIN_USERNAME')) {
if(!defined('SS_DEFAULT_ADMIN_PASSWORD')) {
user_error("SS_DEFAULT_ADMIN_PASSWORD must be defined in your _ss_environment.php,"
. "if SS_DEFAULT_ADMIN_USERNAME is defined. See "
. "http://doc.silverstripe.org/framework/en/topics/environment-management for more information",
E_USER_ERROR);
}
Security::setDefaultAdmin(SS_DEFAULT_ADMIN_USERNAME, SS_DEFAULT_ADMIN_PASSWORD);
}
}); |
The relevant documentation doesn't specify use in |
Perhaps things have changed since the issue was opened. The reason for the behaviour was that Injector was responsible for injecting environment variables at runtime into strings that reference them rather than the confit manifest. Some work was required for the confit manifest to support this functionality instead. |
Those linked docs say this, which maybe indicates the change was deliberate in 4.2:
|
FWIW, my opinion on this has also evolved over the past year. My original goal was to somehow accomplish interpolation of environment variables anywhere in configuration (e.g. via backtick references) and not just under Injector config definitions such as in the original description above. IMHO, really all I ultimately ended up needing and using was a combination of:
Then, I just created one config // Initialize environment variables, making sure not to override any that may already be configured.
// IMPORTANT: Falsey values (empty strings, literal false, etc) may not appear at all in this array.
$envVars = static::config()->Environment ?: [];
foreach($envVars as $envName => $envVal) {
if (Environment::getEnv($envName) === false) {
Environment::setEnv($envName, $envVal);
}
} Then, the developer has the option to manually override (especially temporarily for local development or in emergency scenarios) values committed to EDIT: p.s. Any situations where manual interpolation of environment variables would be needed in |
TL;DR: In favor of not proceeding with this at all and instead utilizing the |
This has to be merged before the CMS5 beta to get in CMS5. |
This didn't make it in CMS 5 - we can look again for 6. |
In SilverStripe 4 we can use backticked environment variables in YAML configuration files, but only if they're under an Injector config definition, e.g.:
This will have Injector call
->setMyProperty()
with the parsed value ofMY_ENV_VAR
when loaded.This is a documented thing, but still something that developers get tripped up on, because you assume it would also apply to other parts of YAML configuration. Example: silverstripe/silverstripe-framework#7987 and https://stackoverflow.com/questions/53437811/silverstripe-env-variable-value-in-config/53459699#53459699
We could add the ability for the configuration layer to parse all environment variables when they're referred to during collection, so that something like this would work too:
So that when
MyServiceClass
calls$this->config()->get('my_config_prop')
it returns the parsed value ofMY_ENV_VAR
from the environment.Acceptance critreria
Note
The text was updated successfully, but these errors were encountered: