Recently there have been at least two posts (Config File Shuffle and Is there such an animal as Config::Simple::VirtualHost?) about configuration management when multiple apps are involved. I answered those questions with brief pointers to Gantry::Conf. This meditation goes into more detail.

Background

A few months ago, my boss came to the bat cave and asked me to make a feature from our customer service call center application available via our customer facing web server. The backend functionality could be shared by the two applications, but that required some shared configuration information.

In another incident, at about the same time, one of our cron scripts failed because its conf was out of sync with the web application it supports.

After these conf headaches, my boss hatched a plan (which is, by itself, evidence of a severe lack of pointy hair). It went like this.

Suppose that on each system there was a single index to all conf for apps which run on that box. In the file is a list of app instances and how they are configured. Each app instance can share conf with other app instances, while having some specific conf for itself.

Finally, for any given bit of conf information there should be many ways to supply it. So, when we give you an app, you don't have to configure it like we do. We usually prefer flat files, you might like LDAP or an SQL database. The choice should belong to the installing admin.

Specifying Conf

Suppose there are two apps we need to deliver: a budgeting tool and a company phone list. The budget is delivered in two instances, providing the same functionality to both the sales and service departments. Each of the apps has a database behind it; those databases live on the same server. Here is one way to configure them:
# The configuration index is in Config::General format. # We store it in /etc/gantry.conf (the default), # but you don't have to. # Everyone shares the database_server_name, # unless their conf overrides it. <global> database_server_name ourdb.example.com </global> # This will be used by the budget application instances. # You could also put the codes in a shared file. # We are all about choice: your choice. <shared codes> petty_cash 10 travel 30 # etc. </shared> # The sales department uses the above codes and shares # the dbconf available via https with the other instances # (this has the database user name and password # for each app). # # budget_sales.conf is listed first, so it takes precedence # over everything else. It defines the database name # and anything else unique to this instance. <instance budget_sales> ConfigureVia FlatFile Config::General /etc/gantry.d/budget_sales.c +onf ConfigureVia HTTP Config::General https://confserver.example.com/d +bconf use codes </instance> # budget_service is exactly like budget_sales, except # it uses budget_service.conf to find its database # name, etc. <instance budget_service> ConfigureVia FlatFile Config::General /etc/gantry.d/budget_service +.conf ConfigureVia HTTP Config::General https://confserver.example.com/d +bconf use codes </instance> # Someone must have liked Config::Tiny at some point, # because this app needs it. <instance phone_list> ConfigureVia FlatFile Config::Tiny /etc/gantry.d/phone_list.conf ConfigureVia HTTP Config::General https://confserver.example.com/ +dbconf </instance>

Deploying Apps

Now suppose that we deploy these web apps via mod_perl.
In the root location for the app we can set a var:
<Location /budget_sales> #... PerlSetVar GantryConfInstance budget_sales </Location>
Then, in the mod_perl handler for the budget application, we can use this to retrieve our conf:
my $conf = Gantry::Conf->retrieve( { instance => $r->dir_config( 'GantryConfInstance' ) });
In fact, this is what our Gantry framework does. If our index file was not in /etc/gantry.conf, we would have added the config_file key to the parameter hash passed to retrieve:
my $conf = Gantry::Conf->retrieve( { instance => $r->dir_config( 'GantryConfInstance' ), config_file => '/etc/gantry.d/standard.conf', } );
For cgi, you could inspect the url looking for your instance, instead of using dir_config on the request object. In cron scripts we can gain the instance from the command line:
use Getopt::Long; my $instance = 'budget_default'; GetOptions( 'instance|i' => \$instance ); my $conf = Gantry::Conf->retrieve( { instance => $instance } );

We hope you enjoy Gantry::Conf as much as we do. And feel free to check out its parent project the Gantry web app frameword: http://www.usegantry.org.

If you have suggestions or comments, we want them.

Phil

Replies are listed 'Best First'.
Re: Configuration Flexibility
by jesuashok (Curate) on Apr 26, 2006 at 11:07 UTC
    Hi

    From your Explanation I Understood of configuring two applications sharing same instances. I mean sharing the Backend Utilities of two application in a single instance.
    I have seen all the Configuration steps. I have done this in my work environment setup. But the performance becomes very slow. Because of accessing mod_perl utility.
    Could you add some more points, which you have left out from the configuration example.
    It will be helpful for me, If you can add the whole configuraion stuffs here.

    "Keep pouring your ideas"
      There is a more detailed introduction to Gantry::Conf in Gantry::Conf::Tutorial.

      But, I'll make a couple of comments I hope are on point. First, you don't need mod_perl to use Gantry::Conf. It doesn't use it. But, it is convinient for mod_perl apps if you already have those.

      Second, when I speak of an instance, it means a particular installation of a piece of software. In my prior example, there was a Budget application deployed in two instances: one for sales, the other for service. To combine backend utilities of two applications, you need to create a new application which uses modules from both of them. Then, the new application can be deployed in one or more instances. Thus, instance (in the context of my posting) refers to a set of configuration which makes an application behave in one way. Adding a second instance of the same application will make it behave in a different way (say by pointing it to a different database, or giving it a new color scheme).

      Third, how you share your 'backend utilities' depends on how your code is factored. For example, in one of our cases we have a remote user management (rum) system which any app could talk to. It's convenient to collect code which talks to it into a single module in any given app. If another app needs to talk in the same way to the rum system, it can simply use the module from the other app. That is where the required share configuration comes in. Talking to the rum system requires certain conf info (think of domain names, port numbers, security credentials, etc). By using the first apps rum contacting module and sharing parts of its conf info, the new system needs only to provide customer suitable front end code.

      Finally, Gantry::Conf, while quite usable, is a work in progress. It does not have caching. This could make it run slow depending on how much load your server is under and how large and complex the conf info is. We welcome discussons (and patches) on how to add caching in controllable ways to improve performance without reducing flexibility.

      If you have further questions you could visit the Gantry framework site http://www.usegantry.org and sign up for the mailing list. Or, you could send private email. See the Gantry source docs for our addresses.

      Phil

Re: Configuration Flexibility
by ides (Deacon) on Apr 26, 2006 at 14:19 UTC

    Finally, after all of these years I have it in writing that I do indeed lack pointy hair! :)

    Great post Phil!

    Frank Wiles <frank@revsys.com>
    www.revsys.com