Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Here's the problem: I have lots of server configuration files written in YAML, one file per server. There are a bunch of servers but actually only a few general types of them according to their respective main purpose (e.g. web servers, DNS servers, MySQL database servers, file servers, etc). However, some servers would be a little different from each other e.g. they have certain specific features turned on or off, etc. And of course each would have unique configuration items like IP address and hostname.

Now I would like to refactor these configuraion files, making them as, say, *.yamlt files where they can later be processed into the final *.yaml files.

The .yamlt file could contain normal YAML, or a reference/"use"/"include" statement followed by another .yaml/yamlt filename, optionally followed by a few specific differences. Sort of a parameterized templating, or inheritance templating, lacking a better terms. Basically for the config of a certain server I want to instruct, "use this type of server as a base, but turn feature A and B off, feature C on."

The YAML structure is a bit complex, sort of like a tree/registry, instead of a simple one-level hash.

Any idea how one might do this?

Replies are listed 'Best First'.
Re: YAML + template/reuse
by moritz (Cardinal) on Nov 30, 2007 at 14:16 UTC
    Well, YAML files are text files, which means you can solve your problem with the usual text templating modules, like Template::Toolkit, Text::Template and even HTML::Template::Compiled.

    Alternatively you can build a default yaml config file and an overriding yaml config, and merge these (for example with Hash::Merge, or "manually") and write a resulting yaml file from the result.

        BTW, when merging can I delete some keys? Something like:

        # parent.yaml foo: bar: 2 baz: 3 # child.yaml foo: bar: 4 # override foo/bar *baz: whatever # undefine baz, prompt users to choose
        OR baz: delete!

        I don't see that option in Hash::Merge. Other module, perhaps?

Re: YAML + template/reuse
by clinton (Priest) on Dec 01, 2007 at 16:54 UTC
    Have a look at Config::Merge (my module). It's purpose is to load configuration trees (ie numerous files in a tree of directories) and to merge them as appropriate into a single hash.

    While there is a default merge scheme, there are hooks available which allow you to make the merge as sophisticated as you like. There is also an example included in the distribution of how one might use file names to indicate which configuration overrides to apply based on machine name - you could alter this to be based on server type etc.

    Feedback welcome :)

    Clint

Re: YAML + template/reuse
by locked_user sundialsvc4 (Abbot) on Nov 30, 2007 at 16:40 UTC

    I feel that the idea of “templating” is quite unnecessary here. “There is another way to do it.”™

    In a situation like this one, there is definitely such a thing as being “too clever.” This approach, in this case, is complexity where simplicity should suffice. (And please note, I mean nothing adverse or personal in such an observation.)

    Simply have one configuration-file that contains the base-settings, then another per-site config which can in some way supersede or augment what's been read from the base-settings file. (If merely “merging” the two hashes, as suggested by others, is sufficient, cool! But if not, there's lots of other things you could do with the two hashes .. base, and site-specific .. to get to where you want to be.

Re: YAML + template/reuse
by Anonymous Monk on Nov 30, 2007 at 14:18 UTC

    Sorry, forgot to add. I could use Perl e.g.:

    # config for server124 $config = YAML::Load('webserver.yamlt'); $config->{network}{ip_addresses} = [qw(10.0.0.124)]; $config->{software}{webserver} = 'apache'; $config->{features}{https} = 0; return YAML::Dump($config);

    But I'd fancy something that is more YAML-ish or template-language-ish, if such thing exists.