Morpheus  Ultimate configuration enginehttp://github.com/druxa/morpheus
Evolutionmy $xml = $ua->get(“http://api.example.com/get”);          This is trivial. And bad if your program is large enou...
Evolutionour $API_HOST = “api.example.com”;...my $xml = $ua->get(“http://$API_HOST/get”);              This is a little bi...
Evolutionmy $conf = Config::General->new(“config_file”);my $API_HOST = $conf->getall->{API_HOST};...my $xml = $ua->get(“http:...
The end?Who needs “ultimate configuration engine”, really...
Only just beginning$conf = Config::General->new(“config_file”);                 Where is this file located?
Which one to choose?$config_file = “./config”;$config_file = “/etc/my-app/config”;$config_file = “$ENV{CONFIG_PATH}/config”;    Who...
Real-world examplesEveryone reinvents configuration from scratch.
Example: git•   ~/.gitconfig + .git/config•   ini-style configs•   git config --list•   GIT_CONFIG env variable
Example: lighttpd• /etc/lighttpd/conf-enabled/*• include “config_file”• include_shell “config_generator.sh”
Example: syslog-ng• one monolythic fileOur system administrators had to write config generation scripts to dealwith this.
Enough!We want to:• separate config providers from consumers  completely• fill config values from any sources we like• make t...
Layers  Your codeConsumer APIs  MorpheusProvider APIs    Users
LayersConsumer APIs  MorpheusProvider APIs
Configuration treeAll configuration values for every program live inone global and dynamic configuration tree.You can think o...
Configuration tree• dynamic - can return different results from  different points of view• assembled from various sources• ...
Layers                   Consumer APIs                       Morpheus                     Provider APIs“Consumer” is a cod...
Consumers                     Consumer APIs/usr/bin/morph        use Morpheus                 defaults                    ...
use Morpheususe Morpheus;$API_HOST = morph(“/MyApp/api_host”);  We’ll explain later how Morpheus can be configured to retur...
Importsuse Morpheus “/MyApp” => [     ‘$api_host’];
Importsuse Morpheus “/MyApp” => [     api_host => ‘$API_HOST’,];
Complex importsuse Morpheus "/foo/bar" => [     qw($V1 $V2 $V3),     "v5" => $V5, "v6/a" => $A,     "v7" => [ $C, $D, "e" ...
/usr/bin/morph$ morph /MyApp{    "api_host" : "api.example.com",    "rate_limit" : 1000}                  If you didn’t re...
/usr/bin/morph$ morph --format=xml /MyApp<opt> <api_host>api.example.com</api_host> <rate_limit>1000</rate_limit></opt>
/usr/bin/morph$ morph --format=tt2 --template=my.tt /MyApp< ... any config format you like ... >     There is also --format...
Setting defaultsuse Morpheus -defaults => {     ‘/MyApp’ => {          api_host => ‘api.example.com’,     },};            ...
Layers       Consumer APIs          Morpheus        Provider APIsAll values are provided by plugins.
Providers Consumer APIs    Morpheus  Provider APIs Bootstrap plugins Runtime plugins    User APIs    Don’t panic!
ProvidersYou’ll only need these 99% of the time                              Provider APIs                           Boots...
Plugins• API: ‘list’ and ‘get’• but not as trivial as you expect• we need more plugins for more config formats
BootstrapBootstrap is a technique for configuring Morpheususing Morpheus itself.Bootstrap plugins fill /morpheus/pluginsname...
Our setupThese are plugins we currently use:Env > DB > File > Defaults
Morpheus::Plugin::Env$ MORPHEUS=‘foo => { bar => 5 }’ morph /foo{    "bar" : 5}                Yes, $ENV{MORPHEUS} contain...
Morpheus::Plugin::DBmysql> SELECT * FROM Morpheus;+----------------------+-----------+| Name          | Config |+----------...
Morpheus::Plugin::File$ cat /etc/foo.cfg$bar = 5;                  We load configs from [qw( ./etc /etc )].       This path...
Perl configs$ cat /etc/MyApp.cfg$API = {   host => ‘api.example.com’,};$ cat /etc/MyApp/API.cfg$host = ‘api.example.com’;$ ...
Perl configs$ cat /etc/foo.cfguse Morpheus;$bar = morph(‘/foo/bar’) + 1; Recursive morph calls work. Unless you’ll introduc...
Perl configs$ cat /etc/MyApp.cfguse Morpheus;my $environment = morph(“/environment”);if ($environment eq ‘development’) {  ...
Perl configs$ cat /etc/MyApp.cfg$API = {   host => ‘api.example.com’,   port => 1234,   rate_limit => 100,};$ cat /etc/MyAp...
Perl configs$ morph /MyApp{  "API" : {    "rate_limit" : 1000,    "port" : 1234,    "host" : "api.example.com"  }}         ...
Future directions•   MooseX::Morpheus•   customizible merging policies•   customazible caching policies•   meta-informatio...
Future directionsBut most important, we need community help.Because we need tons of plugins for compatibilitywith existing...
Contactshttp://search.cpan.org/dist/Morpheushttp://github.com/druxa/morpheusmorpheus-perl@googlegroups.comirc://irc.perl.o...
Upcoming SlideShare
Loading in …5
×

Morpheus configuration engine (slides from Saint Perl-2 conference)

1,863 views
1,790 views

Published on

Morpheus is a very flexible and powerful configuration module.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,863
On SlideShare
0
From Embeds
0
Number of Embeds
319
Actions
Shares
0
Downloads
7
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • Morpheus configuration engine (slides from Saint Perl-2 conference)

    1. 1. Morpheus Ultimate configuration enginehttp://github.com/druxa/morpheus
    2. 2. Evolutionmy $xml = $ua->get(“http://api.example.com/get”); This is trivial. And bad if your program is large enough.
    3. 3. Evolutionour $API_HOST = “api.example.com”;...my $xml = $ua->get(“http://$API_HOST/get”); This is a little bit better, but still bad.
    4. 4. Evolutionmy $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.
    5. 5. The end?Who needs “ultimate configuration engine”, really...
    6. 6. Only just beginning$conf = Config::General->new(“config_file”); Where is this file located?
    7. 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?
    8. 8. Real-world examplesEveryone reinvents configuration from scratch.
    9. 9. Example: git• ~/.gitconfig + .git/config• ini-style configs• git config --list• GIT_CONFIG env variable
    10. 10. Example: lighttpd• /etc/lighttpd/conf-enabled/*• include “config_file”• include_shell “config_generator.sh”
    11. 11. Example: syslog-ng• one monolythic fileOur system administrators had to write config generation scripts to dealwith this.
    12. 12. Enough!We want to:• separate config providers from consumers completely• fill config values from any sources we like• make this mechanism extensible
    13. 13. Layers Your codeConsumer APIs MorpheusProvider APIs Users
    14. 14. LayersConsumer APIs MorpheusProvider APIs
    15. 15. Configuration treeAll configuration values for every program live inone 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. 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. 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. 18. Consumers Consumer APIs/usr/bin/morph use Morpheus defaults Morpheus Provider APIs There are many ways to obtain configuration.
    19. 19. use Morpheususe Morpheus;$API_HOST = morph(“/MyApp/api_host”); We’ll explain later how Morpheus can be configured to return the right value.
    20. 20. Importsuse Morpheus “/MyApp” => [ ‘$api_host’];
    21. 21. Importsuse Morpheus “/MyApp” => [ api_host => ‘$API_HOST’,];
    22. 22. Complex importsuse Morpheus "/foo/bar" => [ qw($V1 $V2 $V3), "v5" => $V5, "v6/a" => $A, "v7" => [ $C, $D, "e" => $E ],];
    23. 23. /usr/bin/morph$ morph /MyApp{ "api_host" : "api.example.com", "rate_limit" : 1000} If you didn’t recognize, this is JSON.
    24. 24. /usr/bin/morph$ morph --format=xml /MyApp<opt> <api_host>api.example.com</api_host> <rate_limit>1000</rate_limit></opt>
    25. 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. 26. Setting defaultsuse 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. 27. Layers Consumer APIs Morpheus Provider APIsAll values are provided by plugins.
    28. 28. Providers Consumer APIs Morpheus Provider APIs Bootstrap plugins Runtime plugins User APIs Don’t panic!
    29. 29. ProvidersYou’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. 30. Plugins• API: ‘list’ and ‘get’• but not as trivial as you expect• we need more plugins for more config formats
    31. 31. BootstrapBootstrap is a technique for configuring Morpheususing Morpheus itself.Bootstrap plugins fill /morpheus/pluginsnamespace with runtime plugins.Bootstrap sets plugin priority order.
    32. 32. Our setupThese are plugins we currently use:Env > DB > File > Defaults
    33. 33. Morpheus::Plugin::Env$ MORPHEUS=‘foo => { bar => 5 }’ morph /foo{ "bar" : 5} Yes, $ENV{MORPHEUS} contains perl code.
    34. 34. Morpheus::Plugin::DBmysql> SELECT * FROM Morpheus;+----------------------+-----------+| Name | Config |+----------------------+-----------+| /foo/bar |5 |+----------------------+-----------+ Config column contains perl code too!
    35. 35. Morpheus::Plugin::File$ cat /etc/foo.cfg$bar = 5; We load configs from [qw( ./etc /etc )]. This path is configurable via /morpheus/plugin/file/options/path
    36. 36. Perl configs$ cat /etc/MyApp.cfg$API = { host => ‘api.example.com’,};$ cat /etc/MyApp/API.cfg$host = ‘api.example.com’;$ cat /etc/MyApp/API/host.cfg‘api.example.com’ These are all the same.
    37. 37. Perl configs$ cat /etc/foo.cfguse Morpheus;$bar = morph(‘/foo/bar’) + 1; Recursive morph calls work. Unless you’ll introduce dependency loop, of course.
    38. 38. Perl configs$ cat /etc/MyApp.cfguse 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. 39. Perl configs$ cat /etc/MyApp.cfg$API = { host => ‘api.example.com’, port => 1234, rate_limit => 100,};$ cat /etc/MyApp.99.cfguse Morpheus;$API = { rate_limit => morph(“/MyApp/API/rate_limit”) * 10 }; ‘99’ is a priority. Default priority is zero.
    40. 40. Perl configs$ morph /MyApp{ "API" : { "rate_limit" : 1000, "port" : 1234, "host" : "api.example.com" }} Morphed!
    41. 41. Future directions• MooseX::Morpheus• customizible merging policies• customazible caching policies• meta-information layer
    42. 42. Future directionsBut most important, we need community help.Because we need tons of plugins for compatibilitywith existing modules:Config::General, Config::INI, Config::JSON, etc.
    43. 43. Contactshttp://search.cpan.org/dist/Morpheushttp://github.com/druxa/morpheusmorpheus-perl@googlegroups.comirc://irc.perl.org#morpheus

    ×