2. Evolution
my $xml = $ua->get(“http://api.example.com/get”);
This is trivial. And bad if your program is large enough.
3. Evolution
our $API_HOST = “api.example.com”;
...
my $xml = $ua->get(“http://$API_HOST/get”);
This is a little bit better, but still bad.
4. Evolution
my $conf = Config::General->new(“config_file”);
my $API_HOST = $conf->getall->{API_HOST};
...
my $xml = $ua->get(“http://$API_HOST/get”);
This version is as far as most coders would go.
7. Which one to choose?
$config_file = “./config”;
$config_file = “/etc/my-app/config”;
$config_file = “$ENV{CONFIG_PATH}/config”;
Who configurates the configurator? And is one config file really enough?
11. Example: syslog-ng
• one monolythic file
Our system administrators had to write config generation scripts to deal
with this.
12. Enough!
We want to:
• separate config providers from consumers
completely
• fill config values from any sources we like
• make this mechanism extensible
13. Layers
Your code
Consumer APIs
Morpheus
Provider APIs
Users
15. Configuration tree
All configuration values for every program live in
one global and dynamic configuration tree.
You can think of this tree as:
• file system
• hashref with lots of nested hashrefs inside
• Windows registry (but not really)
16. Configuration tree
• dynamic - can return different results from
different points of view
• assembled from various sources
• can contain any scalars as values: coderefs,
objects, etc.
17. Layers
Consumer APIs
Morpheus
Provider APIs
“Consumer” is a code which needs some configuration values.
It should never care where these values come from.
18. Consumers
Consumer APIs
/usr/bin/morph use Morpheus defaults
Morpheus
Provider APIs
There are many ways to obtain configuration.
25. /usr/bin/morph
$ morph --format=tt2 --template=my.tt /MyApp
< ... any config format you like ... >
There is also --format=dumper, but I won’t waste another slide on it.
26. Setting defaults
use Morpheus -defaults => {
‘/MyApp’ => {
api_host => ‘api.example.com’,
},
};
This is the first example of *providing* config values.
Now you can use Morpheus instead of ‘use constant’ everywhere!
27. Layers
Consumer APIs
Morpheus
Provider APIs
All values are provided by plugins.
29. Providers
You’ll only need these 99% of the time
Provider APIs
Bootstrap plugins
Runtime plugins
User APIs
At least this will be the case when Morpheus will be mature enough...
30. Plugins
• API: ‘list’ and ‘get’
• but not as trivial as you expect
• we need more plugins for more config formats
31. Bootstrap
Bootstrap is a technique for configuring Morpheus
using Morpheus itself.
Bootstrap plugins fill /morpheus/plugins
namespace with runtime plugins.
Bootstrap sets plugin priority order.
38. Perl configs
$ cat /etc/MyApp.cfg
use Morpheus;
my $environment = morph(“/environment”);
if ($environment eq ‘development’) {
$api_host = “api-dev.example.com”;
}
else {
$api_host = “api.example.com”;
}
Don’t be alarmed. Having this feature available doesn’t mean you have to use it.
39. Perl configs
$ cat /etc/MyApp.cfg
$API = {
host => ‘api.example.com’,
port => 1234,
rate_limit => 100,
};
$ cat /etc/MyApp.99.cfg
use Morpheus;
$API = { rate_limit =>
morph(“/MyApp/API/rate_limit”) * 10 };
‘99’ is a priority. Default priority is zero.
42. Future directions
But most important, we need community help.
Because we need tons of plugins for compatibility
with existing modules:
Config::General, Config::INI, Config::JSON, etc.