-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Override config.php values through environment variables #3966
Conversation
@MorrisJobke, thanks for your PR! By analyzing the history of the files in this pull request, we identified @nickvergessen, @LukasReschke and @bartv2 to be potential reviewers. |
i think it should be nc_ |
Your wish shall be granted 🎆 |
lib/private/Config.php
Outdated
* | ||
* @param string $key key | ||
* @param mixed $default = null default value | ||
* @return mixed the value or $default | ||
*/ | ||
public function getValue($key, $default = null) { | ||
$envValue = getenv(self::ENV_PREFIX . $key); | ||
if ($envValue) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
from http://php.net/manual/en/function.getenv.php
Returns the value of the environment variable varname, or FALSE if the environment variable varname does not exist.
hence I would suggest to explicitly check for that with if ($envValue !== false)
. Not sure which string values PHP considers truthy, but to me this looks error-prone otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, also all int values we have with 0 (log level and rotation, ... ) can not be set otherwise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Do we need casting here? E.g. if you set NC_LOGLEVEL=0
, it will return the string "0"
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about values that should actually be set to false
🙈
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getenv
will always return a string, according to the documentation, so in case of NC_xxx=false
it returns "false"
(string), not false
(bool) 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But for those options we also rely on the fact that there is actual boolean returned if there is a boolean in the config.php 🙈
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed and added unit tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, that's the same problem as in #3966 (comment). Can we handle this somehow? We don't know what the consuming code expects 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per above
lib/private/Config.php
Outdated
* | ||
* If it does not exist, $default will be returned. | ||
* gets its value from an `OC_` prefixed environment variable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OC
-> NC
1ced627
to
6198b22
Compare
@rullzer @icewind1991 @nickvergessen All issues addressed - ready for review |
👍 from me on this |
I feel that it would be better to try and case non-string values to their proper types. maybe try a That would also allow settings things like arrays trough ENV |
* | ||
* @param string $key key | ||
* @param mixed $default = null default value | ||
* @return mixed the value or $default | ||
*/ | ||
public function getValue($key, $default = null) { | ||
$envValue = getenv(self::ENV_PREFIX . $key); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we cache this as well? I think it makes sense. otherwise we might call this hunderd times
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only problem is: How do we know that we need to cache a ENV variable? I can move it below the cache statement, but then the ENV variable would not overwrite config.php values. I guess this is fine. Don't set the config option in config.php, but only in the ENV and it will be used from there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could also just add $this->envCache
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But this would not solve anything for empty env variables, because they are not cached then and the getenv would happen all the time for them.
lib/private/Config.php
Outdated
if (isset($this->cache[$key])) { | ||
return $this->cache[$key]; | ||
} | ||
|
||
$envValue = getenv(self::ENV_PREFIX . $key); | ||
if ($envValue !== false) { | ||
$this->cache[$key] = $envValue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is, that now since the value is in cache, it will be written to the disk when any other config is changed/saved and therefor future changes on the env will not be reflected.
I'd just add it to a second cacheEnv array instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anyway - this second cache array doesn't solve the actual problem: For all entries, that don't have a env variable set the getenv
is still called. And I would say, that most env variables are not used at all -> still the overhead and we don't need to investigate into the cache way of doing it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed this again. I would say that we just check the env variable without any caching.
* added functionality to override config.php values with 'OC_' prefixed environment variables * use getenv to read environment variables since apache does not set $_ENV variables, fixed test Signed-off-by: Morris Jobke <hey@morrisjobke.de>
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
Signed-off-by: Morris Jobke <hey@morrisjobke.de>
29245e6
to
95a21e2
Compare
@ChristophWurst @rullzer @nickvergessen @LukasReschke Ready for review |
Should add to the docs that this is possible, but not recommended |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a big fan but well…
Great change thanks! Do you guys have a suggestion how we could resolve arrays? I'm struggling with setting trusted_domains... this happens when using docker and automatic installation feature. I can do a pull request but I would like to hear how you guys would solve it. Checking for a prefix like "array:" in the ENV and then separating the values by an unusual delimiter like {;} ? |
Keep in mind that config options with "." does not work. You might use another approach for them. I'm not a fan of this at all (and neither the official vm image or docker image use it). It's at least one additonal function call for every system variable. |
Unfortunately it's common nowadays to use container and set the variables (db credentials, etc.) via enviornment variables. Therefore I would really like to see a better support here in nextcloud. |
I think its a better approach to enable getenv only for certain configuration variables like the docker image does: https://github.com/nextcloud/docker/tree/master/.config |
Well you could simply read $_ENV ($_SERVER should usually also contain it) if you want avoid another function call. Even though I don't think that a function call to ENV variables would have a measurable performance impact.
I can't agree on that. Isn't a configuration of an application there to configure it for the environment? So probably most configurations (that are not accessible) are relevant. |
Please use https://help.nextcloud.com/ for discussion or open a new ticket for bug reports. Thanks. |
@LukasReschke @nickvergessen @rullzer @karlitschek Should we rename the env variables to NC_ or should leave them?