Q:

Erlang, override environment

I have an erlang node with some applications. I want to make my applications to fetch their environments variables from some centralized server (e.g. hiera server). Is there any way to override environment variables from .app file, replacing it with custom variables obtained from certain place?
Of course, I don't want to make any changes in my applications code.

A:

If you want to completely avoid changes to your application's code, your best bet is to use an external configuration file and copy from your centralized server to each "local" server. If you specify a file path at the end of your application list in sys.config (assuming you're using releases), the BEAM VM will also load this file as additional configuration.
Using this, you can make a file in a location like /etc/my_service/extended.config and have it automatically update using some service or another. Puppet is an example of a tool that could do that part for you; looks like Hiera (which I'm not familiar with) would be another.
For clarity, with this approach, your sys.config file should look like:
[
    {my_app1, [
            {my_param1, 1},
            {my_param2, "string"}
        ]},
    {my_app2, [
            ...
        ]},
    "/etc/my_service/extended.config"
].

However, that kind of approach has some significant limitations, namely in that the configuration file is only loaded once, and you would have to restart the BEAM VM if you wanted to change it while the service was running. It also works best if you're generating an Erlang release (hence sys.config).
If you're not using an Erlang release and don't have a sys.config file, you can still specify a configuration file using the -config command-line parameter with erl
The best approach, IMO, would require you to make some minor modifications to your application. I would advise storing your parameters in a distributed mnesia table (or any other database, really, so long as you can easily query it). Subsequently, replace your application:get_env/2,3 calls with a call to a function you define which checks the database you are storing settings in before falling back to application:get_env/2,3.
For instance:
-record(setting, {key, value}).
get_setting(App, Key) ->
    get_setting(App, Key, undefined).

get_setting(App, Key, Default) ->
    case mnesia:dirty_read(settings, {App, Key}) of
        [] ->
            application:get_env(App, Key, Default);
        [_ = #setting{value = Value}] ->
            Value
    end.

